zoukankan      html  css  js  c++  java
  • Entity Framework 实体数据模型——LINQ 技巧之一

     一、LINQ 与 EF

      从前面的讨论,可以看到 Code First 模型比 EF 设计模式要精简很多,在实际项目开发中,也建议直接采用 Code First 模式。

      因此,接下来的示例我们都采用 Code First 模式来展开讨论。

      1、Select 语句

        首先,创建 LINQDemo 项目,然后添加 ADO.Net 实体数据模型,选择 Code First 模式,选择事先创建好的数据库。

        接下来,在 Main 方法中写一个 LINQ 的 Select 语句:

         using (var context = new StudentInfoModel())
         {
             var stus = from stu in context.Student select stu;
             foreach (var stu in stus)
             {
                 Console.WriteLine(stu.Name);
             }
         }
         Console.ReadKey();

         

        在 LINQ 中,Select 语句负责查询结果,除了查询完整的对象、单个或特定的属性成员外,同时它还支持功能强大的类型转换功能。

        通过该功能,我们可以借助 LINQ 查询选择的对象集合来创建一组全新的类型(类型转换):

         using (var context = new StudentInfoModel())
         {
             var stus = from stu in context.Student select stu;
     
             foreach (var stu in stus)
             {
                 Console.WriteLine($"姓名:{stu.Name} 	年龄:{stu.Age} 	爱好:{stu.Hobby}");
             }
         }
         Console.ReadKey();

        a、类型转换

        基于上面输出的查询结果,我们可以进行指定属性查询:

        新建一个 SelectResult.cs 类。

         using System;
         using System.Linq;
    
         namespace LINQDemo
         {
             class SelectResult
             {
                 public void GetResult()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         var stus = from stu in context.Student
                                    select new
                                    {
                                        stu.Name,
                                        stu.Age,
                                        stu.Hobby
                                    };
                         foreach (var stu in stus)
                         {
                             Console.WriteLine($"姓名:{stu.Name} 	年龄:{stu.Age} 	爱好:{stu.Hobby}");
                         }
                     }
                 }
             }
         }

        然后回到主程序(Main 方法)中调用该方法:

        

          

        在 Select 语句中获取了指定的 Name、Age、Hobby属性之后,通过 new 关键字创建了新的返回对象。

         

        如你所见,只要通过适当的 LINQ 语句,我们就可以取出特定的数据。

        我们还可以为属性指定标识名:

        

        Select 语句中,在创建的新对象中逐一为属性指定了映射名,同时将原来的年龄减去了 1 岁。

        可以看出,Select 语句除了选择数据外,还进一步转换了结果,创建了新的结果对象类型。创建对象的过程就是所谓的映射。

        在实际开发中,针对特定的数据处理,我们会定义实体类,以支持更进一步的强类型数据操作。

        所以,接下来我们需要定义一个实体类对象,用以存储查询结果及数据处理:

         using System;
         using System.Linq;
    
         namespace LINQDemo
         {
             class SelectResult
             {
                 public void GetResult()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         IQueryable<ResultObj> stus = from stu in context.Student
                                                      select new ResultObj()
                                                      {
                                                          SID = stu.Id,
                                                          StuID = "2020" + stu.Id.ToString(),
                                                          StuName = stu.Name,
                                                          StuAge = stu.Age - 1,
                                                          StuHobby = stu.Hobby
                                                      };
                         foreach (var stu in stus)
                         {
                             Console.WriteLine($"ID:{stu.SID} 	编号:{stu.StuID} 	姓名:{stu.StuName} 	年龄:{stu.StuAge} 	爱好:{stu.StuHobby}");
                         }
                     }
                 }
    
                 class ResultObj
                 {
                     public int? SID { get; set; }
                     public string StuID { get; set; }
                     public string StuName { get; set; }
                     public int? StuAge { get; set; }
                     public string StuHobby { get; set; }
                 }
             }
         }

        

        这么看来,感觉 Select 语句有点儿复杂,有什么方法可以简化么?

        当然,我们可以把 new 对象的逻辑单独的放到独立的方法(或函数)中:

         public void GetResult()
         {
             using (var context = new StudentInfoModel())
             {
                 IEnumerable<ResultObj> stus = from stu in context.Student.ToList()
                                               select ConvertToResultObj(stu);
                 foreach (var stu in stus)
                 {
                     Console.WriteLine($"ID:{stu.SID} 	编号:{stu.StuID} 	姓名:{stu.StuName} 	年龄:{stu.StuAge} 	爱好:{stu.StuHobby}");
                 }
             }
         }
    
         ResultObj ConvertToResultObj(Student stu)
         {
             return new ResultObj()
             {
                 SID = stu.Id,
                 StuID = "2020" + stu.Id.ToString(),
                 StuName = stu.Name,
                 StuAge = stu.Age - 1,
                 StuHobby = stu.Hobby
             };
         }

      2、多重 from 与 SelectMany

        了解了 Select 语句后,再来学习 SelectMany 就会容易许多,因为 SelectMany 只是搭配了多重 from 子句的 Select 方法。

        // 第二个参数 Func<TSource, IEnumerable<TResult>> selector 
        // IEnumerable<TResult> 这个表示将 IEnumerable 对象当做参数传入做进一步处理,构成了多重 from 运算。
    public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source,
                                                  Func<TSource, IEnumerable<TResult>> selector);

        在学习 SelectMany 方法之前,先来看两个多重 from 语句的例子:

         using System;
         using System.Linq;
     
         namespace LINQDemo
         {
             class Program
             {
                 static void Main(string[] args)
                 {
                     string[] weekMonth = { "January,February,March,April,May,June,July,August,September,October,November,December",
                                            "Monday,Tusday,Wednesday,Thursday,Friday,Saturday,Sunday" };
     
                     var enumMonth = from wm in weekMonth
                                     from daywm in wm.Split(',')
                                     select new
                                     {
                                         week = daywm.Contains("day") ? daywm.Substring(0, 3):"",
                                         month = !daywm.Contains("day") ? daywm.Substring(0, 3):"",
                                     };
    
                     string month = "星期的缩写:
    ";
                     foreach (var mon in enumMonth)
                     {
                         if(mon.week!="")
                             month += mon.week + "
    ";
                     }
                     Console.WriteLine(month);
     
                     month = "月份的缩写:
    ";
                     foreach (var mon in enumMonth)
                     {
       month += mon.month + " ";
    } Console.WriteLine(month); Console.ReadKey(); } } }

        

        上面的例子是将数组中的数据提取成缩写形式并输出!用了嵌套 from 语句。

        第一个 from 语句是将月份和星期提取出来,第二个 from 将提取出来的对象通过 ‘,’ 将其分解,然后再挨个处理数组中的数据;

        最后返回一个由 week 和 month 属性组成的匿名对象。像这种就是嵌套查询了。

        接下来,咱们用 LINQ 结合 EF 实体数据结构,来看看多重 from 是怎么操作的?

        首先,需要添加一个年级表,学生表能添加一个关联年级表的ID,表结果如下:

        Student 表:

        

        ClassGrade 表:

        

        年级表和学生表 是一对多的关系。

        接下来我们尝试用 LINQ 语句,将学生用年级来分组并输出:

         using System;
         using System.Linq;
     
         namespace LINQDemo
         {
             class SelectMany
             {
                 public void ClassToStu()
                 {
                     using(var context = new StudentInfoModel())
                     {
                         var stus = from classes in context.CGrade
                                    from stu in classes.Students
                                    orderby classes.GradeNum,classes.ClassNum
                                    select new
                                    {
                                        classes.GradeNum,
                                        classes.ClassNum,
                                        stu.Name
                                    };
     
                         foreach (var stu in stus)
                         {
                             Console.WriteLine($"{stu.GradeNum}年级{stu.ClassNum}班:	{stu.Name}");
                         }
                     }
                 }
             }
         }

        

        我们通过 LINQ 实现了归组链表查询,接下来看看如何把上面的 LINQ 语句通过 SelectMany() 方法来实现:

         using System;
         using System.Linq;
     
         namespace LINQDemo
         {
             class SelectMany
             {
                 public void ClassToStu()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         var students = context.CGrade.SelectMany(
                             s => s.Students.Select(
                                 st => new
                                 {
                                     s.GradeNum,
                                     s.ClassNum,
                                     st.Name
                                 })).OrderBy(s => s.GradeNum).ThenBy(s => s.ClassNum);
    
                         foreach (var stu in students)
                         {
                             Console.WriteLine($"{stu.GradeNum}年级{stu.ClassNum}班:	{stu.Name}");
                         }
                     }
                 }
             }
         }

        我们还可以通过 where 方法来过滤出我们想要查询的数据,比如 我想查出属于一年级的同学:

         var stus = from classes in context.CGrade where classes.GradeNum == 1
                     from stu in classes.Students
                     orderby classes.GradeNum, classes.ClassNum
                     select new
                     {
                         classes.GradeNum,
                         classes.ClassNum,
                         stu.Name
                     };
    
         var students = context.CGrade.Where(s => s.GradeNum == 1).SelectMany(
                     s => s.Students.Select(
                         st => new
                         {
                             s.GradeNum,
                             s.ClassNum,
                             st.Name
                         })).OrderBy(s => s.GradeNum).ThenBy(s => s.ClassNum);

      3、Where 与数据筛选

        数据筛选过滤运算是针对集合中的对象元素,根据指定的条件返回符合此条件值的数据记录。

        与数据的筛选运算有关的方法有两个,它们分别是 where 与 OfType。

        我们先来看看 where,下面示例过滤出 15 到 17 岁的童鞋:

         using System;
         using System.Collections.Generic;
         using System.Linq;
         using System.Text;
         using System.Threading.Tasks;
     
         namespace LINQDemo
         {
             class Where
             {
                 public void GetWhereData()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         Console.WriteLine("LINQ 语句:");
                         var students = from stu in context.Student
                                        where stu.Age >= 15 && stu.Age <= 17
                                        select stu;
      
                         foreach (var stu in students)
                         {
                             Console.WriteLine($"{stu.Name}:	{stu.Age}");
                         }
     
                         Console.WriteLine("
    Where 方法:");
                         students = context.Student.Where(s => s.Age >= 15 && s.Age <= 17);
                         foreach (var stu in students)
                         {
                             Console.WriteLine($"{stu.Name}:	{stu.Age}");
                         }
                     }
                 }
             }
         }

        如你所见,LINQ 已完美整合进 C# 语法中,我们可以再套用标准的 C# 语法或其他的 C# 运算符,进而建立更为复杂的筛选表达式。

         using System;
         using System.Collections.Generic;
         using System.Linq;
     
         namespace LINQDemo
         {
             class Where
             {
                 public void DoWhere()
                 {
                     int[] numberQuery = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
                
                     string source = "列表数据:";
                     foreach (var num in numberQuery)
                     {
                         source += num + ",";
                     }
                     Console.WriteLine(source + "
    ");
     
                     IEnumerable<int> enumNumbers = from number in numberQuery
                                                    where number <= 20 && number >= 10
                                                    select number;
                     string result = "查询10-20之间的数字:";
                     foreach (var num in enumNumbers)
                     {
                         result += num + ",";
                     }
                     Console.WriteLine(result + "
    ");
     
                     enumNumbers = from number in numberQuery
                                   where IsEven(number)
                                   select number;
                     result = "查询偶数:";
                     foreach (var num in enumNumbers)
                     {
                         result += num + ",";
                     }
                     Console.WriteLine(result);
                 }
     
                 public bool IsEven(int value)
                 {
                     bool val = (value % 2) == 0;
                     return val;
                 }
             }
         }

        可以看到 where 条件中调用了 IsEven 方法,来判断传值是否为偶数并返回结果,程序会根据此结果决定筛选的数据。

        但是,当 LINQ 计算的数据记录是直接连接到底层数据进行存取时,由于牵涉 SQL 语句的转换问题,所以在  where

        子句中引用独立函数时会出现无法解析的问题,因此必须将数据完全载入之后才能进一步运算。

         using System;
         using System.Collections.Generic;
         using System.Linq;
         using System.Text;
         using System.Threading.Tasks;
    
         namespace LINQDemo
         {
             class Where
             {
                 public void DoWhere()
                 {
                     using(var context = new StudentInfoModel())
                     {
                         IEnumerable<Student> students = from stu in context.Student
                                                         where IsAgeRange(stu.Age)
                                                         select stu;
                         Console.WriteLine("查询 16-18 岁的学生:");
                         foreach (var stu in students)
                         {
                             Console.WriteLine($"{stu.Name} 	{stu.Age}");
                         }
                     }
                 }
    
                 private bool IsAgeRange(int? age)
                 {
                     bool b = age >= 16 && age <= 18;
                     return b;
                 }
             }
         }

        如同上面的示例,因为 IsAgeRange 方法无法被解析,所以就会出现如下错误:

        

        我们需要将 LINQ 语句进行 ToList 转换,以确保程序的正常运行:

         IEnumerable<Student> students = from stu in context.Student.ToList()
                                         where IsAgeRange(stu.Age)
                                         select stu;

        这么一来,由于数据完成了转换,所以程序得以正常运行:

        

      4、OfType 方法

        如果想要通过类型来筛选集合对象,可以通过引用 IEnumerable 的扩充方法 OfType 来实现。

        对未导入泛型技术的旧型项目进行维护时,通过 OfType 可以很方便地对特定类型进行筛选。

          实践出真知,上例子:

         using System;
         using System.Collections;
         using System.Collections.Generic;
         using System.Linq;
    
         namespace LINQDemo.Demo
         {
             class OfType
             {
                 public void OfTypeDemo()
                 {
                     ArrayList arrayList = new ArrayList()
                     {
                         "Mon","Tue","Wed","Thu","Fri","Sat","Sun",
                         "1", "2", "3", "4", "5", "6", "7",
                         1,2,3,4,5,6,7,
                     };
     
                     Console.WriteLine("ArrayList 中的数据:");
                     foreach (var al in arrayList)
                     {
                         Console.WriteLine(al.ToString() + ",");
                     }
     
                     IEnumerable<string> arrList = arrayList.OfType<string>();
              IEnumerable<string> strList = from strl in arrList select strl;
                     Console.WriteLine("
    
    OfType<string> 的筛选结果:");
                     foreach (var al in strList)
                     {
                         Console.WriteLine(al.ToString() + ",");
                     }
                 }
             }
         }

        OfType 方法可以将传统的集合转换成支持 LINQ 查询的 IEnumerable 对象,它会只筛选符合类型的对象。

        这个方法相当实用, 现在结合实体数据模型进行

         using System;
         using System.Collections;
         using System.Collections.Generic;
         using System.Linq;
         using System.Text;
         using System.Threading.Tasks;
     
         namespace LINQDemo.Demo
         {
             class OfType
             {
                 public void DoOfType()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         var grands = from cg in context.CGrade.ToList()
                                      select GetStudent(cg);
                         IEnumerable<rStudent> rStudents = grands.OfType<rStudent>();
                         foreach (var stus in rStudents)
                         {
                             Console.WriteLine($"{stus.Name} 的全部学生:");
                             foreach (var st in stus.Stus)
                             {
                                 Console.WriteLine($"	{st.Name}");
                             }
                         }
                     }
                 }
    
                 private object GetStudent(ClassGrade cg)
                 {
                     if (cg.GradeNum == 1)
                     {
                         rStudent rStudent = new rStudent()
                         {
                             Id = cg.CGId,
                             Name = $"{cg.GradeNum}年级{cg.ClassNum}班",
                             Stus = cg.Students
                         };
                         return rStudent;
                     }else
                     {
                         return cg;
                     }
                 }
    
                 public class rStudent
                 {
                     public int Id { get; set; }
                     public string Name { get; set; }
                     public IEnumerable<Student> Stus { get; set; }
                 }
             }
         }

        上面的例子通过 OfType 方法过滤出了属于一年级每个班级的童鞋:

        

      5、排序

        排序是查询操作中非常普遍的行为,LINQ 根据指定的对象属性对集合元素进行排序。

        LINQ 中的排序方法:

        OrderBy (升序排序)、OrderByDescending(降序排序)、ThenBy(二次升序排序)、ThenByDescending(二次降序排序)以及

        Reverse(反转集合中的对象排列顺序)

        屏上得来终觉浅,觉知此事得执行:

         using System;
         using System.Linq;
    
         namespace LINQDemo.Demo
       {
             class OrderBy
             {
                 public void GetDataOrderBy()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         // LINQ 语句
                         var stus = from stu in context.Student
                                    orderby stu.Age, stu.Name
                                    select stu;
    
                         //OrderBy、ThenBy方法
                         var stu_met = context.Student.OrderBy(s => s.Age).ThenBy(s => s.Name);
                         foreach (var stu in stus)
                         {
                             Console.WriteLine($"姓名:{stu.Name} 	年龄:{stu.Age}");
                         }
                     }
                 }
             }
         }

        看下执行结果,如果没有出错的话,大概是按照年龄升序进行排序的:

        

        降序排序只需在字段后面加上 descending 即可:

          // LINQ 语句
       var stus = from stu in context.Student orderby stu.Age descending select stu;
       //OrderByDescending 方法
    var stu_met = context.Student.OrderByDescending(s => s.Age);
         // LINQ 语句
         var stus = from stu in context.Student
                    orderby stu.Age descending, stu.Name descending
                    select stu;
         //OrderBy、ThenBy方法
         var stu_met = context.Student.OrderByDescending(s => s.Age).ThenByDescending(s => s.Name);

          多字段进行排序的话,需用 “,” (逗号) 进行分隔(先以年龄排序,再通过名称排序):

         // LINQ 语句
         var stus = from stu in context.Student
                    orderby stu.Age, stu.Name
                    select stu;
         //OrderBy、ThenBy方法
         var stu_met = context.Student.OrderBy(s => s.Age).ThenBy(s => s.Name);

        

        排序的痕迹有没有很明显?

        反转输出

        Reverse 是排序的方法之一,不过它并没有对应的 C# 语句,必须直接进行引用。

        Reverse 方法不需要任何参数。

        心动么?行动吧,再不行动,女神都老啦:

         using System;
         using System.Linq;
     
         namespace LINQDemo.Demo
         {
             class Reverse
             {
                 public void DoReverse()
                 {
                     using(var context = new StudentInfoModel())
                     {
                         var stus = context.Student.OrderBy(s => s.Age).ToList();
                         stus.Reverse();
                         foreach (var stu in stus)
                         {
                             Console.WriteLine($"姓名:{stu.Name} 	年龄:{stu.Age}");
                         }
                     }
                 }
             }
         }

        

      6、分组

        分组通过一个指定的 key 返回分组化的数据内容,相关的语句有两种:group-by 和 group-by-into。

        ① group-by

        group 表示将要查询的数据源进行分组,其后必须连接所要搜索的集合对象,by 则是指定作为分组依据的条件值。

        分组运算返回的是一种 IGrouping<TKey, TElement> 类对象,表示一系列具有共同键值的对象集合,集合元素则

        通过此键值辨识元素所属分组,因此我们可以通过分组运算来自定义逻辑,以达到将集合中的对象进行分类的目的。

        干就完了:

         using System;
         using System.Collections.Generic;
         using System.Linq;
    
         namespace LINQDemo.Demo
         {
             class GroupDemo
             {
                 public void DoGroup()
                 {
                     List<int> monthList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
                     // LINQ 
                     IEnumerable<IGrouping<int, int>> query = from month in monthList
                                                              group month by checkMonth(month);
                     // GroupBy 方法
                     IEnumerable<IGrouping<int, int>> query2 = monthList.GroupBy(month => checkMonth(month));
                     foreach (var group in query)
                     {
                         Console.WriteLine(group.Key > 30 ? "每月31天" : group.Key < 30 ? "二月" : "每月30天");
                         foreach (var i in group)
                         {
                             Console.WriteLine($"{i}-{group.Key.ToString()}");
                         }
                         Console.WriteLine("
    ");
                     }
                 }
     
                 public int checkMonth(int month)
                 {
                     int resultDays;
                     resultDays = DateTime.DaysInMonth(2020, month);
                     return resultDays;
                 }
             }
         }

        上面示例给每个月按照天数进行了分组归类:

        

        ② group-by-into

        into 表示指定一个暂存的标识变量,用来存储每一个分组后的结果,然后针对每一个分组结果进一步执行其他的查询运算。

        into 最后会将分组的结果存储于指定的标识变量中,因此一旦启用 into 就必须进一步在其后编写处理表达式,然后以 select

        或另一个 group 作为结束。

        把上例中的 LINQ 语句进行调整下:

         // LINQ 
         IEnumerable<IGrouping<int, int>> query = from month in monthList
                                                  group month by checkMonth(month) into o
                                                  orderby o.Key
                                                  select o;  //into 把分组结果的引用存储给了指定变量 o,然后通过 Key 对其进行了排序。
         // GroupBy 方法  用 Select 实现 into 的功能
         IEnumerable<IGrouping<int, int>> query2 = monthList.GroupBy(month => checkMonth(month)).Select(g => g).OrderBy(g => g.Key);

         

        可以看到月份分组按照天数进行排序了。

        接下来,结合 ADO.NET 实体数据模型来探讨下数据库的分组操作。

        直接看示例吧:

         using System;
         using System.Collections.Generic;
         using System.Linq;
    
         namespace LINQDemo.Demo
         {
             class GroupDemo
             {
                 public void DoADOGroup()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         IEnumerable<IGrouping<int?, Student>> groups = from stu in context.Student
                                                                        group stu by stu.Age;
                         foreach (var gp in groups)
                         {
                             Console.WriteLine(gp.Key + "岁的童鞋:");
                             foreach (var stu in gp)
                             {
                                 Console.WriteLine($"姓名:{stu.Name} 	{stu.Age}");
                             }
                             Console.WriteLine("
    ");
                         }
                     }
                 }
             }
         }

        还是看结果吧:

        

        我们还可以将分组的规则进行进一步的封装,以便简化 LINQ 语句:

         using System;
         using System.Collections.Generic;
         using System.Linq;
     
         namespace LINQDemo.Demo
         {
             class GroupDemo
             {
                 public void DoGroupToMethod()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         IEnumerable<IGrouping<string, Student>> gps = from stu in context.Student.ToList()
                                                                       group stu by CheckAge(stu.Age ?? 0);
       
                         foreach (var gp in gps)
                         {
                             Console.WriteLine(gp.Key);
                             foreach (var stu in gp)
                             {
                                 Console.WriteLine($"姓名:{stu.Name} 	年龄:{stu.Age}");
                             }
                             Console.WriteLine("
    ");
                         }
                     }
                 }
     
                 string CheckAge(int age)
                 {
                     if (age >= 18) return "成年";
                     else if (age >= 16 && age <= 18) return "青年";
                     else return "少年";
                 }
             }
         }

         

        通过这种方式我们可以写更复杂的分组处理逻辑。

        group-by-into 同样也可以结合 ADO.NET 实体数据模型来处理数据。

         using System;
         using System.Collections.Generic;
         using System.Linq;
     
         namespace LINQDemo.Demo
         {
             class GroupDemo
             {
                 public void GroupInto()
                 {
                     using (var context = new StudentInfoModel())
                     {
                         IEnumerable<IGrouping<int, ClassGrade>> gps = from cg in context.CGrade.ToList()
                                                                       group cg by cg.GradeNum into cgp
                                                                       orderby cgp.Key 
                                                                       select cgp;
                         foreach (var gp in gps)
                         {
                             Console.WriteLine($"{gp.Key}年级:");
                             foreach (var cg in gp)
                             {
                                 foreach (var stu in cg.Students)
                                 {
                                     Console.WriteLine($"姓名:{stu.Name}  	班级:{cg.ClassNum}班");
                                 }
                              }
                              Console.WriteLine("
    ");
                         }
                     }
                 }
             }
         }

        

         OK,篇幅过长…来日方长!拜了个拜!

  • 相关阅读:
    css的一些属性及其属性值
    HTML基本标签
    JQuery
    js中的Dom事件模型以及表格方面等内容
    Alpha的过程总结
    数独+GUI界面
    数独
    调研《构建之法》指导下的全国高校的历届软工实践作品、全国互联网+竞赛、物联网竞赛、华为杯研究生作品赛、全国大学生服务外包赛等各类全国性大学生信息化相关的竞赛平台的历届作品
    本学期高级软件工程课程的实践项目的自我目标
    高级软件工程第八次作业:“两只小熊队”团队作业-5
  • 原文地址:https://www.cnblogs.com/LittleBai/p/14102843.html
Copyright © 2011-2022 走看看