Asp.net Mvc教学:LINQ to Objects和 LINQ to Entities的经典案例-由Deepseek产生

张开发
2026/5/14 11:45:10 15 分钟阅读

分享文章

Asp.net Mvc教学:LINQ to Objects和 LINQ to Entities的经典案例-由Deepseek产生
下面分别给出LINQ to Objects操作内存集合和LINQ to Entities通过 EF Core 操作数据库的 4 个典型案例。案例使用 C# 编写并附带简要说明。一、LINQ to Objects4 个案例适用于ListT,T[],IEnumerableT等内存中的集合。案例 1筛选Where与投影Select场景从学生列表中找出成绩大于 80 分的男生只返回姓名和成绩。publicclassStudent{publicstringName{get;set;}publicintScore{get;set;}publicstringGender{get;set;}}voidMain(){ListStudentstudentsnewListStudent{newStudent{Name张三,Score85,Gender男},newStudent{Name李四,Score92,Gender男},newStudent{Name王芳,Score78,Gender女},newStudent{Name赵磊,Score88,Gender男}};varresultstudents.Where(ss.Score80s.Gender男).Select(snew{s.Name,s.Score});foreach(variteminresult)Console.WriteLine(${item.Name}-{item.Score});// 输出张三 - 85, 李四 - 92, 赵磊 - 88}案例 2排序OrderBy / ThenBy场景按成绩降序排列成绩相同则按姓名升序。varsortedstudents.OrderByDescending(ss.Score).ThenBy(ss.Name);foreach(varsinsorted)Console.WriteLine(${s.Name}:{s.Score});案例 3分组GroupBy场景按性别分组统计每组人数和平均分。vargroupsstudents.GroupBy(ss.Gender).Select(gnew{Genderg.Key,Countg.Count(),AvgScoreg.Average(xx.Score)});foreach(vargingroups)Console.WriteLine(${g.Gender}共{g.Count}人平均分{g.AvgScore:F1});案例 4连接Join场景两个集合学生表和班级表通过班级 ID 连接显示学生及其班级名称。publicclassStudentWithClassId{publicstringName{get;set;}publicintClassId{get;set;}}publicclassClass{publicintId{get;set;}publicstringName{get;set;}}voidMain(){ListStudentWithClassIdstudentsnewListStudentWithClassId{newStudentWithClassId{Name张三,ClassId1},newStudentWithClassId{Name李四,ClassId2},};ListClassclassesnewListClass{newClass{Id1,Name一班},newClass{Id2,Name二班}};varjoinedstudents.Join(classes,studentstudent.ClassId,clscls.Id,(student,cls)new{student.Name,ClassNamecls.Name});foreach(variteminjoined)Console.WriteLine(${item.Name}属于{item.ClassName});}二、LINQ to Entities4 个案例假设使用Entity Framework Core上下文为SchoolDbContext包含DbSetStudent和DbSetClass。查询会被翻译成 SQL 执行。案例 1筛选与投影场景查询数据库中成绩大于 80 分的男生只返回姓名和成绩。using(varcontextnewSchoolDbContext()){varresultcontext.Students.Where(ss.Score80s.Gender男).Select(snew{s.Name,s.Score}).ToList();// 此时执行 SQLforeach(variteminresult)Console.WriteLine(${item.Name}-{item.Score});}案例 2排序 取前 N 条场景按成绩降序取前 3 名的学生。using(varcontextnewSchoolDbContext()){vartop3context.Students.OrderByDescending(ss.Score).Take(3).ToList();foreach(varsintop3)Console.WriteLine(${s.Name}:{s.Score});}案例 3分组聚合GroupBy场景按性别分组统计每组人数和最高分。using(varcontextnewSchoolDbContext()){vargroupStatscontext.Students.GroupBy(ss.Gender).Select(gnew{Genderg.Key,Countg.Count(),MaxScoreg.Max(xx.Score)}).ToList();foreach(vargingroupStats)Console.WriteLine(${g.Gender}共{g.Count}人最高分{g.MaxScore});}注意EF Core 会将上述 GroupBy 转换为 SQL 的GROUP BY不会将数据全部拉到内存。案例 4跨表连接Join / Include场景查询学生及其所属班级名称。两种写法方法 A使用 Join类似 SQLusing(varcontextnewSchoolDbContext()){varquerycontext.Students.Join(context.Classes,ss.ClassId,cc.Id,(s,c)new{s.Name,ClassNamec.Name}).ToList();}方法 B使用导航属性推荐如果模型已配置关系// 假设 Student 实体包含 public Class Class { get; set; }varresultcontext.Students.Include(ss.Class)// 避免 N1 问题.Select(snew{s.Name,ClassNames.Class.Name}).ToList();关键区别总结特性LINQ to ObjectsLINQ to Entities数据源内存集合List, Array等数据库通过 EF Core执行方式立即执行委托直接调用延迟执行生成 SQL 语句支持的方法几乎所有 LINQ 运算符受 SQL 限制例如不能随意调用自定义 C# 方法典型终止操作.ToList(),.First(),.Count()等同样需要.ToList()等来触发 SQL 执行掌握这两者基本就能覆盖绝大多数 .NET 日常开发中的数据查询需求。继续补充LINQ to Objects和LINQ to Entities各 4 个新案例避免与上一组重复。一、LINQ to Objects追加 4 例案例 5聚合函数Min, Max, Sum, Average场景对一组订单金额进行计算获取总额、最高金额、最低金额、平均金额。ListdoubleorderAmountsnewListdouble{99.5,150.0,320.8,45.2,270.3};doubletotalorderAmounts.Sum();doublemaxorderAmounts.Max();doubleminorderAmounts.Min();doubleavgorderAmounts.Average();Console.WriteLine($总额{total}最高{max}最低{min}平均{avg:F2});案例 6集合操作Distinct, Union, Intersect, Except场景两个兴趣集合求并集、交集、差集、去重。ListstringgroupAnewListstring{篮球,足球,游泳};ListstringgroupBnewListstring{足球,羽毛球,游泳};varuniongroupA.Union(groupB);// 并集篮球,足球,游泳,羽毛球varintersectgroupA.Intersect(groupB);// 交集足球,游泳varexceptgroupA.Except(groupB);// 差集篮球vardistinctgroupA.Distinct();// 本身去重本例无变化Console.WriteLine($并集{string.Join(,,union)});Console.WriteLine($交集{string.Join(,,intersect)});Console.WriteLine($差集{string.Join(,,except)});案例 7元素操作First, Last, Single 及 OrDefault 版本场景从集合中获取特定位置的元素安全处理空值。ListintnumbersnewListint{10,20,30,40,50};ListintemptyListnewListint();intfirstnumbers.First();// 10intlastnumbers.Last();// 50intfirstEvennumbers.First(nn%200);// 20// 安全版本不存在时返回默认值不抛异常intfirstOrDefaultemptyList.FirstOrDefault();// 0intsingleOrDefaultnumbers.SingleOrDefault(nn100);// 0// Single要求集合中恰好有一个匹配元素intonlyOnenewListint{100}.Single();// 100案例 8量词操作Any, All, Contains场景判断集合中是否存在满足条件的元素或是否全部满足。ListintagesnewListint{18,20,25,17,30};boolhasMinorages.Any(ageage18);// true有17岁boolallAdultages.All(ageage18);// false存在17boolcontains25ages.Contains(25);// trueif(hasMinor)Console.WriteLine(存在未成年人);二、LINQ to Entities追加 4 例仍假设使用 EF Core上下文为AppDbContext实体如Product含Name, Price, Category, CreatedAt、Order等。案例 5模糊查询与日期范围筛选场景查询名称包含“手机”的产品且生产日期在去年全年范围内。using(varcontextnewAppDbContext()){varstartDatenewDateTime(2025,1,1);varendDatenewDateTime(2025,12,31);varproductscontext.Products.Where(pEF.Functions.Like(p.Name,%手机%)p.CreatedAtstartDatep.CreatedAtendDate).ToList();}EF.Functions.Like会被翻译成 SQL 的LIKE比Contains更灵活。案例 6分页Skip Take场景每页显示 10 条商品按价格升序获取第 3 页的数据。intpageNumber3;intpageSize10;using(varcontextnewAppDbContext()){varpagecontext.Products.OrderBy(pp.Price).Skip((pageNumber-1)*pageSize).Take(pageSize).ToList();}案例 7子查询与 Exists用 Any 实现场景查询所有下过订单的客户即客户在 Orders 表中存在关联记录。using(varcontextnewAppDbContext()){// 方法1直接使用 Any 子查询会被翻译为 EXISTSvarcustomersWithOrderscontext.Customers.Where(ccontext.Orders.Any(oo.CustomerIdc.Id)).ToList();// 方法2Join 后 Distinct效率通常不如 AnyvarcustomersWithOrders2context.Customers.Join(context.Orders,cc.Id,oo.CustomerId,(c,o)c).Distinct().ToList();}案例 8多级分组GroupBy 多个字段场景按商品分类和上架年份分组统计每组的商品数量和平均价格。using(varcontextnewAppDbContext()){varquerycontext.Products.GroupBy(pnew{p.Category,Yearp.CreatedAt.Year}).Select(gnew{g.Key.Category,g.Key.Year,Countg.Count(),AvgPriceg.Average(pp.Price)}).OrderBy(rr.Category).ThenBy(rr.Year).ToList();foreach(variteminquery)Console.WriteLine(${item.Category}-{item.Year}{item.Count}件均价{item.AvgPrice:F2});}EF Core 会将CreatedAt.Year翻译为 SQL 的YEAR(CreatedAt)支持常见日期函数。再次总结两组案例的核心区别操作类型LINQ to ObjectsLINQ to Entities自定义方法调用✅ 完全支持如自定义比较器❌ 仅支持 EF Core 映射的函数延迟执行内存中遍历时执行生成 SQLToList()时执行异常处理直接抛出 .NET 异常可能抛出数据库相关异常性能考虑数据量过大时 O(n) 扫描依赖数据库索引和查询优化如果需要更多案例如SelectMany、Zip、ToDictionary等我可以继续提供。

更多文章