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,篇幅过长…来日方长!拜了个拜!

  • 相关阅读:
    __name__使用方法,模块查找顺序和模块的绝对导入
    模块
    ATM程序结构
    迭代器
    常用内置方法
    生成式,匿名函数及内置函数部分使用方法
    算法之二分法和三元表达式
    redis配置文件
    PythonStudy——shutil 模块
    PythonStudy——pickle 模块 (泡菜)
  • 原文地址:https://www.cnblogs.com/LittleBai/p/14102843.html
Copyright © 2011-2022 走看看