【LINQ】 记录C#上的Linq学习【一】

961 阅读3分钟

前言

才工作时对Linq了解很少,结果工作上的难题证明了做后端编码,就一定要学会Linq。
首先不得不吹一波Microsoft的大神们,把Linq这个基础包做的非常厉害,
.Net Framework 3.5 以上直接引入命名空间就可以使用了。

using System.Linq;

这篇文章到底要表达什么

  1. 这不是写技术教程,也不是搬运官方文档,很多技术也是受别人指教学习。
  2. 分享我在项目中实际遇到的问题,不同于网上的Demo教程。
  3. 欢迎指出我的不足,谢谢。

案例一:多个list关联查询。

初始化代码
public class Person()
{
    public int Cardnum {get;set;}
    public string Name {get;set;}
    public Empinfo Info {get;set;}
}

public class Empinfo()
{
    public int DepId { get; set;}
    public string WorkNum {get;set;}
}

public class Department()
{   
    public int Id {get;set;}
    public string Name {get;set;}
}

List<Department> dep = new List<Department>()
{
    new Department(){ Id = 1, Name = "开发部"},
    new Department(){ Id = 2, Name = "背锅部"},
    new Department(){ Id = 3, Name = "运营部"}
}

List<Person> per = new List<Person>()
{
    new Person(){ Cardnum= 1, Name = "张三", Info = new Empinfo() { DepId = 1,WorkNum = "第一组" } },
    new Person(){ Cardnum= 2, Name = "李四", Info = new Empinfo() { DepId = 2,WorkNum = "第二组" } },
    new Person(){ Cardnum= 3, Name = "王五", Info = new Empinfo() { DepId = 3,WorkNum = "第三组" } },
    new Person(){ Cardnum= 4, Name = "赵六", Info = new Empinfo() { DepId = 1,WorkNum = "第一组" } },
    new Person(){ Cardnum= 5, Name = "陈七", Info = new Empinfo() { DepId = 2,WorkNum = "第二组" } }
};

可以看到以上的人员和部门关联点是在于 per.info.depId == dep.Id
需求是根据per查询出每个部门下有多少人

先来一段传统代码
public class Templist()
{
    public int DepId { get; set;}
    public string Name {get;set;}
    public int Count {get;set}
}

List<Templist> temps = new List<Templist>();

foreach(depitem in dep )
{
    foreach(pitem in per)
    {
        if(pitem.info.DepId == depitem.Id)
        {
            temps.add()
            ...
        }
    }
}

当然还有性能更差一点的for循环也可以实现。
我的上述代码还没写完:判断temps是否重复,count++统计,是否有null的情况……
完成这个功能估计要是30行左右的代码。 是不是非常繁琐?

linq 优化

Join操作符。常应用于将多个数据源相联接,根据数据源中相等的值进行匹配

var result = from d in dep
            join p in per on dep.Id equals p.EmpInfo.DepId
            into g
            select new
            {
                DepartId = d.Id,
                DepartName = d.Name,
                Count = g.Count()
            };

看到这里我相信没有使用过Linq的同学一定开始惊讶Linq的魔力了。
减少代码并不是关键,而把复杂的嵌套循环直接改用类似T-SQL的语法,既减轻了代码复杂度,又提升了美观。

案例二: 去重和查询

存在多条重复数据时,该怎么查询和去重呢?

去重的条件一般都是指向性:比如要求通过卡号去重,保留考勤时间最大的一条。

public class AttendInfo
{
    public int CardNum { set; get; }
    public string Name { set; get; }
    public int DepId { set; get; }
    public DateTime AttendTime { set; get; }
}

List<AttendInfo> lists = new List<AttendInfo>()
{
    new AttendInfo(){ CardNum = 1, Name = "张三", DepId = 1, AttendTime = DateTime.Parse("2019-01-01 00:00:00")},
    new AttendInfo(){ CardNum = 1, Name = "张三", DepId = 1, AttendTime = DateTime.Parse("2019-01-02 00:00:00")},
    new AttendInfo(){ CardNum = 2, Name = "李四", DepId = 2, AttendTime = DateTime.Parse("2019-01-03 00:00:00")},
    new AttendInfo(){ CardNum = 2, Name = "李四", DepId = 2, AttendTime = DateTime.Parse("2019-01-04 00:00:00")},
    new AttendInfo(){ CardNum = 3, Name = "王五", DepId = 3, AttendTime = DateTime.Parse("2019-01-05 00:00:00")},
    new AttendInfo(){ CardNum = 3, Name = "王五", DepId = 3, AttendTime = DateTime.Parse("2019-01-06 00:00:00")},
    new AttendInfo(){ CardNum = 4, Name = "赵六", DepId = 4, AttendTime = DateTime.Parse("2019-01-07 00:00:00")}
};

Linq官方给出的建议是: lists.Distinct(); 

但是这个方法在实际项目中很少能用到,因为你的数据结构不可能这么单一
并且还带有搜索条件,所以应该这么写.

var temp = from ls in lists
            group ls by ls.CardNum
            into g
            select new
            {
                CardNum = g.Key,
                Name = g.Max(e => e.Name),
                DepId = g.Max(e => e.DepId),
                AttendTime = g.Max(e => e.AttendTime)
            };
            
group by 分组后,操作对象非常轻松。


结束语

这些小案例只是Linq的常规用法,但能发现Linq无论大小都能将数据处理变得更轻松,便捷。
在此也鞭策自己,不为前端接口考虑后端性能优化的程序员,不是一个合格的全栈(/笑