第三十六讲 LINQ to DataSet

回顾
    1. 前三节以LINQ TO OBJECT 作为依托,对LINQ的基础,语法,技巧做了详细的讨论和演示
    
    2. LINQ查询适用于实例IEnumerable<T>接口或IQueryable<T>接口的数据源
    
    3. LINT TO OBJECT表示一种新的处理集合的方法
        1. 它们更简明,更易读,尤其在筛选多个条件时。
        2. 它们使用最少的应用程序代码提供强大的筛选,排序和分组功能
        3. 无需要修改或只需要做很小的修改即可将它们移植到其他数据源。
        
主要内容
    准备27讲的数据库
    
    1. LINQ TO DATASET概念
        DataSet的结构
            表-->数据行
        DataSet查询功能
            1. 筛选和排序 -->select()
            2. 层次结构导航-->GetChildRows() GetParentRow()
            3. 更复杂的情况-->纯手工() -->Linq to DataSet
            
        LINQ to DataSet功能主要通过下面两个类的扩展方法公开
            1. DataRowExtensions
            2. DataTableExtensions
            
        有截图
            
    2. LINQ TO DATASET和N层架构
        已经截图
    
    3. 使用LINQ查询DATASET
        1. 只能查询已经有数据的DataSet
        2. LINQ查询可以对DataSet中的单个表执行
        3. 使用join和GroupJoin运算符对多个表执行
        4. 要查询DataSet必须先调用AsEnumerable方法,将数据源转换下
        
            
            
    4. 单表查询
    访问DataRow列值
        1. Field方法:获取列的值
        2. SetField方法:设置列的值
        3. Field方法和SetField方法的泛型参数T中指定的数据类型必须与基础值的类型相匹配。
    
    5. 交叉表查询
        LINQ框架提供两个连接运算符
            1. join: join实现内部连接
            2. GroupJoin: 实现内部连接和左外连接的超集
            
        执行同等连接,即仅在键相等时匹配两个数据源的连接。
        
如:单表查询
    实例中的dt是一个方法,返回一个数据集DataSet,AsEnumerable()方法是将这个数据集转换成LINQ语法中必须的数据类型,只有这样DataSet才能支持LINQ查询
    
    实例中Dataset对象中的字段.Field方法提供对DataRow列值的访问,而setField方法应该是对列值写的访问。

    var query=
        from p in dt.AsEnumerable()
        where p.Field<int>("id") ==2
        select new{
            ID=p.Field<int>("id"),
            Name=p.Field<string>("name"),
            Price=p.Field<decimal>("price"),
            Number=p.Field<int>("number"),
            Classify="分类二"
        };
        
如:交叉表查询
    同样通过一个方法返回DataSet类型的两个数据表
    DataTable dt_product=GetFillDataSet().Tables["product"];
    DataTable dt_classify=GetFillDataSet().Tables["classify"];
    
    //接下来创建查询,其中使用了Join关键字
    var query=
        from c in dt_classify.AsEnumerable()
        join p in dt_product.AsEnumerable()
        on c.Field<int>("id") equals p.Field<int>("c_id")
        select new{
            //投影出新对象
            //最好在为新投影对象属性赋值的时候判断字段值是否为空,否则将引发IvailidCastException错误
            ID=p.Field<int>("id"),
            Name=p.Field<string>("name"),
            Price=p.Field<decimal>("price"),
            Number=p.Field<int>("number"),
            Classify=c.Field<string>("name")
        };
        
        
如:GroupJoin的操作实例
    1. 下面的关于GroupJoin的实例对Lambda以及表达式树的理解要求较高
    2. 看不懂就反复的做和改,理解其中的原理
    
    同上面一样获取的两张表,只是类型不同了
    IEnumerable<DataTable> products=GetFillDataSet().Tables["product"].AsEnumerable();
    IEnumerable<DataTable> classify=GetFillDataSet().Tables["classify"].AsEnumerable();
    
    var dt_query=
        classify.GroupJoin(products,
            cls => cls.Field<int>("id"),
            pro => pro.Field<int>("c_id"),
            //下面括号里的两个变量都啥意思?
            (c,plist) => new{
                Cname=c.Field<string>("name"),
                List=plist.Select(s=>s)
            }            
        );
    //先将两个表整出来以GroupJoin连接并对比,cls,pro这就是分别从两个表中抽出来作对比的字段。

    //"=>" 这个运算符就是委托运算符。
    //上面的(c,plist)两个变量,分别是classify表和products表类型的变量。其中plist的类型是IEnumerable<第二序列中的元素类型集合>的变量
    

看了我上面的笔记,是不是很简单,有没有动手敲一下冲动,敲吧兄弟,木敲过你是永远不会的,这是真的。我敲了,但是也不一定会呢,我人笨呢,老师说了他学的时候GroupJoin这个方法都不那么容易理解,我敲了,也跟踪了一下,结果晕了!没看出所以然来。因这就是系统预定义好的,TMD想看懂它是怎么整出来的,还是真不容易。类似于"XXX<T>"这种模式的预定义方法,大多是系统定义好的匿名委托,不知道这么说会不会误人子弟,这是我的个人见解,其实老师也说了些有关此类的描述。期待高人指正!!!像IEnumerable,IEnumerator这些东东,说是可以使用foreach进行简单迭代的集合,而GroupJoin这个方法,目前以我的水平也只知道,它可以用在两个表的交叉查寻中,可以分层显示结果,就好像我练习中写的那样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace Con36
{
    class Program
    {

        /// <summary>
        /// Linq to Dataset实例操作
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //数据库连接字符串
            string strCon = "server=.; database=OneDb; uid=sa; pwd=123123;";
            string sqlSelect = "select id,name,sex,age from People";
            string sqlSelect2 = "select id,bname,price,class from Books";
            string sqlSelect3 = "select class,cname from Class";
            DataSet ds;
            using (SqlConnection conn = new SqlConnection(strCon))
            {
                //SqlDataAdapter sda = new SqlDataAdapter();
                SqlDataAdapter sda = new SqlDataAdapter(sqlSelect, conn);
                ds = new DataSet();
                sda.Fill(ds, "people");
                sda.SelectCommand = new SqlCommand(sqlSelect2, conn);
                sda.Fill(ds, "Books");
                sda.SelectCommand = new SqlCommand(sqlSelect3, conn);
                sda.Fill(ds, "Class");

            }
            //从数据集中获取一个表出来,我个人理解是Linq只能对确定了表名的表进行操作
            //直接使用数据集对象是不行滴
            DataTable dt = ds.Tables["people"];
            DataTable dt2 = ds.Tables["Books"];
            DataTable dt3 = ds.Tables["Class"];

            Console.WriteLine("\n==========People表查寻=============\n");

            //使用Linq对单表操作
            var table = from t in dt.AsEnumerable() //使用前先转换成IEnumberable<T>类型
                        select new
                        {
                            id = t.Field<int>("id"),
                            name = t.Field<string>("name"),
                            sex = t.Field<string>("sex"),
                            age = t.Field<int>("age")
                        };
            foreach (var d in table)
            {
                Console.WriteLine("用户ID={0}, 用户名({1}), 性别({2}), 年龄({3})", d.id, d.name, d.sex, d.age);
            }

            Console.WriteLine("\n==========Books表查寻=============\n");

            var table2=from t2 in dt2.AsEnumerable()
                       select new{
                         id=t2.Field<int>("id"),
                         bname=t2.Field<string>("bname"),
                         price=t2.Field<decimal>("price"),
                         //说明一下,我数据库里的class字段定义的是char类型,但是这里不能用char,否则会报错
                         cid=t2.Field<string>("class") 
                       };
            foreach (var d2 in table2)
            {
                Console.WriteLine("书ID={0}, 书名({1}), 书价({2}), 书类别({3})", d2.id, d2.bname, d2.price, d2.cid);
            }


            Console.WriteLine("\n==========使用Join=============\n");
            var table3 = from t3 in dt3.AsEnumerable()
                         //这里说一下我测试出现的问题,Books和Class这两个表,在创建时由class字段的数据类型有差异不能正常
                         //显示结果,Books中的class字段是char(1)类型(长度),而Class中的class字段是char(2),很幼稚的错误吧
                         join t4 in dt2.AsEnumerable() on t3.Field<string>("class") equals t4.Field<string>("class")
                         select new {
                             id = t4.Field<int>("id"),
                             bname = t4.Field<string>("bname"),
                             price = t4.Field<decimal>("price"),
                             cid = t3.Field<string>("cname") 
                         };

            foreach (var d3 in table3)
            {
                Console.WriteLine("书ID={0}, 书名({1}), 书价({2}), 类名({3})", d3.id, d3.bname, d3.price, d3.cid);
            }

            Console.WriteLine("\n==========使用GroupJoin,听老师讲的老难了=============\n");
            //这里我还是学老师的操作吧,先把要查寻的表转换成IEnumerable<T>类型
            IEnumerable<DataRow> idr1 = dt2.AsEnumerable();//前面把表从数据集里抽出来,这里再行从DataTable中抽出来
            IEnumerable<DataRow> idr2 = dt3.AsEnumerable();

            var table4 = idr2.GroupJoin(idr1,
                i1 => i1.Field<string>("class"),
                i2 => i2.Field<string>("class"),
                (x1, y1) => new
                {
                    cid = x1.Field<string>("class"),
                    cname = x1.Field<string>("cname"),
                    sList = y1.Select(s => s)
                });

            foreach (var v in table4)
            {
                Console.WriteLine("\n======类编号:{0}====类别名:{1}=======\n",v.cid,v.cname);
                foreach (DataRow dr in v.sList)
                { 
                    string id = dr["id"].ToString();
                    string bname = dr["bname"].ToString();
                    string price = dr["price"].ToString();
                    string cid = v.cname;

                    Console.WriteLine("书ID={0}, 书名({1}), 书价({2}), 类名({3})", id, bname, price, cid);
                }
            }


            Console.ReadKey();

            //帮助文档里的解释

            //TOuter:第一个序列中的元素的类型。
            //TInner:第二个序列中的元素的类型。
            //TKey:键选择器函数返回的键的类型。
            //TResult:结果元素的类型。

            //public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
            //    this IEnumerable<TOuter> outer,//outer:要联接的第一个序列(集合)。
            //    IEnumerable<TInner> inner,//inner:要与第一个序列联接的序列。
            //    Func<TOuter, TKey> outerKeySelector,//用于从第一个序列的每个元素提取联接键的函数。
            //    Func<TInner, TKey> innerKeySelector,//用于从第二个序列的每个元素提取联接键的函数。
            //    Func<TOuter, IEnumerable<TInner>, TResult> resultSelector //用于从第一个序列的元素和
            //第二个序列的匹配元素集合中创建结果元素的函数。
            //)

        }
    }

    #region MSDN中的实例代码 连接地址:http://127.0.0.1:47873/help/0-4816/ms.help?method=page&id=
    //M%3ASYSTEM.LINQ.ENUMERABLE.GROUPJOIN%60%604(SYSTEM.COLLECTIONS.GENERIC.IENUMERABLE%7B%60%600%7D%2CSYSTEM.COLLECTIONS.GENERIC.IENUMERABLE%7B%60%601%7D%2CSYSTEM.FUNC%7B%60%600%2C%60%602%7D%2CSYSTEM.FUNC%7B%60%601%2C%60%602%7D%2CSYSTEM.FUNC%7B%60%600%2CSYSTEM.COLLECTIONS.GENERIC.IENUMERABLE%7B%60%601%7D%2C%60%603%7D)&product=VS&productVersion=100&topicVersion=100&locale=ZH-CN&topicLocale=ZH-CN
    //    class Person
    //{
    //    public string Name { get; set; }
    //}

    //class Pet
    //{
    //    public string Name { get; set; }
    //    public Person Owner { get; set; }
    //}

    //public static void GroupJoinEx1()
    //{
    //    Person magnus = new Person { Name = "Hedlund, Magnus" };
    //    Person terry = new Person { Name = "Adams, Terry" };
    //    Person charlotte = new Person { Name = "Weiss, Charlotte" };

    //    Pet barley = new Pet { Name = "Barley", Owner = terry };
    //    Pet boots = new Pet { Name = "Boots", Owner = terry };
    //    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    //    Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

    //    List<Person> people = new List<Person> { magnus, terry, charlotte };
    //    List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };

    //    // Create a list where each element is an anonymous 
    //    // type that contains a person's name and 
    //    // a collection of names of the pets they own.
    //    var query =
    //        people.GroupJoin(pets,
    //                         person => person,
    //                         pet => pet.Owner,
    //                         (person, petCollection) =>
    //                             new
    //                             {
    //                                 OwnerName = person.Name,
    //                                 Pets = petCollection.Select(pet => pet.Name)
    //                             });

    //    foreach (var obj in query)
    //    {
    //        // Output the owner's name.
    //        Console.WriteLine("{0}:", obj.OwnerName);
    //        // Output each of the owner's pet's names.
    //        foreach (string pet in obj.Pets)
    //        {
    //            Console.WriteLine("  {0}", pet);
    //        }
    //    }
    //}

    ///*
    // This code produces the following output:

    // Hedlund, Magnus:
    //   Daisy
    // Adams, Terry:
    //   Barley
    //   Boots
    // Weiss, Charlotte:
    //   Whiskers
    //*/ 
    #endregion

}
还是控制台好测试,用窗口还要调示控件。同时也可以让朋友们更好测试,要不你还真得要看清楚每个按钮的代码对应关系。希望对您有帮助,加油,加油,加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值