• LINQ 常规实践总结


    1.Linq 执行多列排序

    OrderBy的意义是按照指定顺序排序,连续两次OrderBy,后面一个有可能会打乱前面一个的排序顺序,可能与预期不符。

    要实现sql中的order by word,name类似效果; LINQ 有ThenBy可以紧接使用, ThenBy记住原本排序的值,然后再排其他值, 正因如此,ThenBy是针对IOrderEnumerable 进行调用的。

    2. Linq主外键连接查询

    group join操作符常用于返回‘主键对象-外键对象集合’的查询,例如‘产品类别-此类别下所有的产品’的模式。

      // 查询语法
     var query =  
            from c in db.Categories  
            join p in db.Products on c.CategoryID equals p.CategoryID into r  
            select  new  
            {  
                c.CategoryName,  
                Products = r  
            };  
     // 方法语法   
     var q =  
            db.Categories  
            .GroupJoin  
            (  
               db.Products,  
               c => c.CategoryID,  
               p => p.CategoryID,  
               (c, p) => new  
               {  
                   c.CategoryName,  
                   Products = p  
               }  
            );  
      这样就可以结合 DefaultIfEmpty 理解 left outer join的linq写法。

     group join生成的sql接近于:

    select Categories.*, Products.* from Categories 
    left join Products on  Categories.Id = Products.CateId 
    order by Categories.Id 
    
     // group join 有点类似于 left join 数据膨胀的效果

    https://docs.microsoft.com/en-us/dotnet/csharp/linq/perform-grouped-joins

    3.linq2sql 指定形成sql左右连接

      linq2sql join语法默认得到的是inner join

     Model1Container model = new Model1Container();
                //内连接
                var query = from s in model.Student
                            join c in model.Course on s.CourseCno equals c.Cno
                            where c.Cno == 1
                            select new
                            {
                                ClassID = s.CourseCno,
                                ClassName = c.Cname,
                                Student = new
                                {
                                    Name = s.Sname,
                                    ID = s.Sno
                                }
                            };
        foreach (var item in query)
        {
            Response.Write("ClassID:" + item.ClassID + "ClassName:" + item.ClassName + "Name:" + item.Student.Name);
        }

     在sql profile里面监控到与上面Linq2sql 对应的sql是

    SELECT [t0].[CourseCno] AS [ClassID], [t1].[Cname] AS [ClassName], [t0].[Sname] AS [Name], [t0].[Sno] AS [ID]
    FROM [Student] AS [t0]
    INNER JOIN [Course] AS [t1] ON [t0].[CourseCno] = [t1].[Cno]
    WHERE [t1].[Cno] = @p0

      linq2sql 左连接

    Model1Container model = new Model1Container();
                var query = from s in model.Student
                            join c in model.Course on s.CourseCno equals c.Cno into gc
                            from gci in gc.DefaultIfEmpty()
                            select new
                            {
                                ClassID = s.CourseCno,
                                ClassName = gci ==null ?String.Empty: gci.Cname,
                                Student = new
                                {
                                    Name = s.Sname,
                                    ID = s.Sno
                                }
                            };
        //Outer join时必须将join后的表into到一个新的变量gc中,然后要用gc.DefaultIfEmpty()表示外连接(没有匹配的记录字段设为NULL)
        
        foreach (var item in query)
        {
            Response.Write("ClassID:" + item.ClassID + "ClassName:" + item.ClassName + "Name:" + item.Student.Name);
        }
        
       // 上例中使用了DefaultIfEmpty操作符,它能够为Empty序列(注意是Empty序列而不是Null序列)返回一个默认元素序列,DefaultIfEmpty使用了泛型中的default关键字。
        
        gc.DefaultIfEmpty(new Course { Cname = "",Cperiod="" } )    //设置为空时的默认值
        

     与以上Linq2sql对应的sql 是

    SELECT [t0].[CourseCno] AS [ClassID], [t1].[Cname] AS [ClassName], [t0].[Sname] AS [Name], [t0].[Sno] AS [ID]
    FROM [Student] AS [t0]
    LEFT OUTER JOIN [Course] AS [t1] ON [t0].[CourseCno] = [t1].[Cno]

     https://docs.microsoft.com/en-us/dotnet/csharp/linq/perform-left-outer-joins

    4. 忽略Linq 检索某元素异常

    在日常Linq实践中,按照某种预期写定的Linq, 在执行检索时某些元素会爆出异常,导致整个检索失败;如果我们能容忍某些元素的异常,继续完成整个Linq检索,可以写一个扩展方法,忽略报错元素。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
     
    namespace Enumerable {
        public static class EnumerableExtension {
            /// <summary>
            /// 在IEnumerable<T> 循环或者变为内存序列之前 忽略掉序列中存在的元素异常
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="values"></param>
            /// <returns></returns>
            public static IEnumerable<T> SkipException<T> (this IEnumerable<T> values) {
                using(var enumerator = values.GetEnumerator()) {
                    var next = true;
                    while(next) {
                        try{
                            // 如果枚举器成功推进到下一个元素,MoveNext为true;枚举数越过集合结尾,则为false,也就是说返回值只确定后续是否有值
                            next = enumerator.MoveNext();
                        } catch{
                            // catch到异常,忽略当前元素,继续循环
                            LogHelper.Write("cause exception", LogHelper.LogMessageType.Error);
                            continue;
                        }
                        // yield 返回枚举器指向的当前元素
                        if(next)
                            yield  return enumerator.Current;
                    }
                }
            }
        }
    }

    这个扩展方法的思路是  重写foreach语法糖的默认逻辑:

           能够使用foreach语法的序列必定实现IEnumerable接口,此处我们重写了该接口的默认迭代器使用方式。

        

    作者:JulianHuang

    感谢您的认真阅读,如有问题请大胆斧正,如果您觉得本文对你有用,不妨右下角点个或加关注。

    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置注明本文的作者及原文链接,否则保留追究法律责任的权利。

  • 相关阅读:
    冲刺会议第七天
    冲刺会议第六天
    冲刺会议第五天
    冲刺会议第四天
    题目
    关于小程序开发者和体验者的数据请求问题
    focus、blur事件的事件委托处理(兼容各个流浏览器)
    收集的一些技术论坛博客
    ios下fixed回复框bug的解决方案
    jQuery的13个优点
  • 原文地址:https://www.cnblogs.com/JulianHuang/p/10334812.html
Copyright © 2020-2023  润新知