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

    一、转换

      无论是 Select 还是 Group,最后返回的都是可枚举的集合对象。

      而 LINQ 有一组专门用于元素转换的操作,可以将指定的序列转换成特定的类型。

      1、AsEnumerable

        如果想要将一个特定的集合对象转换为 IEnumerable<T> 类型的对象,也可以通过调用 AsEnumerable 方法达到转换效果。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace LINQDemo.Demo
    {
        class ConvertDemo
        {
            public void DoAsEnumerable()
            {
                EmployeeList<Employee> employees = new EmployeeList<Employee>()
                {
                    new Employee {ID=104,Name="赵老师",Salary=5000,Department="体育组"},
                    new Employee {ID=101,Name="张老师",Salary=6000,Department="数学组"},
                    new Employee {ID=102,Name="王老师",Salary=7000,Department="化学组"},
                    new Employee {ID=103,Name="李老师",Salary=80000,Department="历史组"}
                };
    
                Console.WriteLine(employees.Average(e => e.Salary));
                Console.WriteLine(employees.AsEnumerable().Average(e => e.Salary));
            }
        }
    
        class EmployeeList<T> : List<T>
        {
            public decimal Average(Func<T, decimal> s)
            {
                var list = (List<T>)this;
                decimal age = list.Average(s) * Decimal.Parse("0.1");
                return age;
            }
        }
    
        public class Employee
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public int Salary { get; set; }
            public string Department { get; set; }
        }
    }

        AsEnumerable() 方法可以让调用此方法的对象从一般的集合对象转换成 IEnumerable 的集合对象,以支持 LINQ 运算。

        比如 ADO.NET 的 DataTable 不支持 LINQ 运算,我们可以通过调用 DataTableExtensions.AsEnumerable 方法进行转换。

        转换后将返回 EnumerableRowCollection<DataRow> 对象,该对象支持 LINQ 运算。

    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Linq;
    
    namespace LINQDemo.Demo
    {
    
        class ConvertDemo
        {
            public void TableAsEnumrtable()
            {
                string conStr = @"data source=...";   //数据库的链接地址
                SqlConnection conn = new SqlConnection(conStr);
                SqlCommand cmd = new SqlCommand("select * from Student", conn);
                conn.Open();
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataTable dt = new DataTable();
                da.Fill(dt);
                conn.Close();
                da.Dispose();
    
                EnumerableRowCollection<DataRow> stus = from stu in dt.AsEnumerable()
                                                        select stu;
                foreach (var st in stus)
                {
                    Console.WriteLine($"姓名:{st.Field<string>("Name")} 	年龄:{st.Field<int>("Age")}");
                }
            }
        }
    }

        我们还可以优化下取值结构:

    var stus = from stu in dt.AsEnumerable()
                select new { 
                    Name = stu.Field<string>("Name"),
                    Age = stu.Field<int>("Age")
                };
    foreach (var st in stus)
    {
       Console.WriteLine($"姓名:{st.Name} 	年龄:{st.Age}");
    }

      2、Array 与 List

        Array 和 List 是常见的集合对象种类,我们可以通过 ToArray 或 ToList 这两个方法进行集合的转换。

        ToArray 和 ToList 都是将指定的 source 转换为对应的类型对象来返回的。这两个方法返回的是 source

        序列内容元素的复本。

        无论是 Array 还是 List,转换操作都非常有用,特别是我们想改变 LINQ 查询运算结果的类型时,

        他提供的转换功能可以让我们很方便地在各种类型之间进行切换。

        先来看看 Array 与 List 之间的转换:

    public void DoArrayList()
    {
        List<string> weekDay = new List<string>() { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
        string[] weekDayArray = weekDay.ToArray();
        for (int i = 0; i < weekDayArray.Length; i++)
        {
            Console.WriteLine($"{weekDayArray[i]} ");
        }
        Console.WriteLine("
    ");
        List<string> weekDayList = weekDayArray.ToList();
        foreach (var day in weekDayList)
        {
            Console.WriteLine($"{day} ");
        }
    }

        在具体的实现中,ToList 方法经常被运用于 List<T> 的转换。

    using System;
    using System.Data;
    using System.Linq;
    
    namespace LINQDemo.Demo
    {
    
        class ConvertDemo
        {
            public void ToList()
            {
                using (var context = new StudentInfoModel())
                {
                    IQueryable<Student> list = from stu in context.Student
                                               where CheckAge(stu.Age ?? 0)
                                               select stu;
    
                    Console.WriteLine($"大于 16 岁的学生有 {list.Count()} 人。");
                }
            }
    
            bool CheckAge(int age)
            {
                if (age > 16) return true;
                else return false;
            }
        }
    }

        执行之后会报错:

        

        这个错误是因为程序尝试将 CheckAge 方法转换成数据库引擎认可的合法语句时失败了导致的。

        在这种情况下,我们可以先将其转换成 List 对象(先取数据),然后再对 List 对象进行 were 运算。

    using System;
    using System.Data;
    using System.Linq;
    
    namespace LINQDemo.Demo
    {
    
        class ConvertDemo
        {
            public void ToList()
            {
                using (var context = new StudentInfoModel())
                {
                    IQueryable<Student> query = from stu in context.Student
                                                select stu;
                    var list = from stu in query.ToList()
                               where CheckAge(stu.Age ?? 0)
                               select stu;
    
                    Console.WriteLine($"大于 16 岁的学生有 {list.Count()} 人。");
                }
            }
    
            bool CheckAge(int age)
            {
                if (age > 16) return true;
                else return false;
            }
        }
    }

        如果需要将复杂的对象集合转换成对应的单个属性数组,ToArray 也相当有用:

    public void ToArray()
    {
        using (var context = new StudentInfoModel())
        {
            string[] list = (from stu in context.Student select stu.Name).ToArray();
            for (int i = 0; i < list.Length; i++)
            {
                Console.WriteLine(list[i]);
            }
        }
    }

        我们也可以将 List 对象转换成 IQueryable 对象。

    public void ToList()
    {
        using (var context = new StudentInfoModel())
        {
            IQueryable<Student> query = from stu in context.Student
                                        select stu;
            var list = from stu in query.ToList()
                        where CheckAge(stu.Age ?? 0)
                        select stu;
            list.AsQueryable();    // 直接调用AsQueryable() 方法即可
            Console.WriteLine($"大于 16 岁的学生有 {list.Count()} 人。");
        }
    }

      3、ToDictionary 方法

        我们可以使用 ToDictionary 方法将指定的序列集合转换成 Dictionary 类型对象。

    /// <param name="source">需要转换的源对象</param>
    /// <param name="keySelector">用来获取对应到每一个元素项的 key 值。
    ///                           Dictionary 是以 key/value 类型存储的集合元素,因此必须指定这个参数作为key值的源,且不能重复。</param>
    public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

        想要获取 Dictionary 集合中的 key 及其相应的元素,必须通过一个名为 KeyValuePair 的结构进行存取。

        KeyValuePair 结构被定义在 System.Collections.Generic 命名空间中,它被定义成了 key/value 对(键值对)。

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

    public void ToDictionaryStu()
    {
        List<string> liStu = new List<string>() { "吴二", "张三", "王五", "赵六", "田七" };
    
        int indexValue = 0;
    
        Dictionary<string, string> stuDic = liStu.ToDictionary(keyValue => "stu-" + (indexValue++).ToString());
        foreach (KeyValuePair<string, string> dic in stuDic)
        {
            Console.WriteLine($"{dic.Key} 	{dic.Value}");
        }
    }

        

        然后再结合ADO.NET数据模型来看看:

    public void ToDictionaryAdo()
    {
        using (var context = new StudentInfoModel())
        {
            IQueryable<Student> stus = from stu in context.Student select stu;
    
            Dictionary<string, Student> dic = stus.ToDictionary(key => key.Age + "_" + key.Id);
    
            foreach (var stu in dic)
            {
                Console.WriteLine($"{stu.Key} 	{stu.Value.Name} 	{stu.Value.Sex}");
            }
        }
    }

        

        如果是要取指定的某个值的话(比如取学生名称),我们还可以这么来处理:

    public void ToDictionaryAdoGetValue()
    {
        using (var context = new StudentInfoModel())
        {
            IQueryable<Student> stus = from stu in context.Student select stu;
    
            Dictionary<string, string> dic = stus.ToDictionary(key => key.Age + "_" + key.Id, key => key.Name);
    
            foreach (var stu in dic)
            {
                Console.WriteLine($"{stu.Key} 	{stu.Value}");
            }
        }
    }

        

        不同的地方就是转换类型变了,一个返回的是 Dictionary<string, Student> 类型,而另一个则是 Dictionary<string, string> 类型。

      4、ToLookup

        ILookup 是一对多的 Dictionary 类型对象,与 Dictionary 的差异在于:

        ILookup 的 key/value 是一对多的关系,集合中的 key 会映射到一组包含多个项值的集合;

        而 Dictionary 则是一对一的关系。

        直接看示例吧,简单易理解:

    public void DoToLookup()
    {
        List<string> listStu = new List<string> { "Tom", "Jerry","吴二", "张三", "王五", "赵六", "田七" };
    
        int i = 0;
        ILookup<string, string> lookup = listStu.ToLookup(key => "name");
        foreach (IGrouping<string, string> igp in lookup)
        {
            Console.WriteLine(igp.Key);
            foreach (string str in igp)
            {
                Console.WriteLine(str);
            }
        }
    }

         

        可以看出来,ToLookup 把所有的姓名都归拢到一个 key 里了。

        接下来结合 ADO.NET 实体数据模型来瞧瞧:

    public void DoToLookupAdo()
    {
        using (var context = new StudentInfoModel())
        {
            IQueryable<Student> stus = from stu in context.Student select stu;
    
            ILookup<bool?, Student> look = stus.ToLookup(key => key.Sex);
    
            foreach (var group in look)
            {
                Console.WriteLine($"
    {group.Key}");
                foreach (var gp in group)
                {
                    Console.WriteLine($" {gp.Id} 	{gp.Name}");
                }
            }
        }
    }

         

        可以看出来,程序按照 True (男)和 False (女)对学生进行了归组分类。

        和 Dictionary 一样,ToLookup 也可以指定取特定的值,比如取名称:

    public void DoToLookupAdoGetValue()
    {
        using (var context = new StudentInfoModel())
        {
            IQueryable<Student> stus = from stu in context.Student select stu;
    
            ILookup<bool?, string> look = stus.ToLookup(key => key.Sex, key => key.Name);
    
            foreach (var group in look)
            {
                Console.WriteLine($"
    {group.Key}:");
                foreach (var gp in group)
                {
                    Console.WriteLine($"    {gp}");
                }
            }
        }
    }

        

  • 相关阅读:
    Android Studio 优秀插件: Parcelable Code Generator
    Android Studio 优秀插件:GsonFormat
    DrawerLayout(抽屉效果)
    Python拼接字符串的七种方式
    Python爬虫教程-使用chardet
    Python爬虫教程-实现百度翻译
    Tensorflow分布式部署和开发
    简单的Python GUI界面框架
    用keras构建自己的网络层 TensorFlow2.0教程
    Python GUI教程一:Hello World
  • 原文地址:https://www.cnblogs.com/LittleBai/p/14132511.html
Copyright © 2011-2022 走看看