.NET:使用 LinqSharp 简化复杂查询

LinqSharp 是个开源 LINQ 扩展库,它允许您编写简单代码来生成复杂查询,包括查询扩展和动态查询生成。

LinqSharp.EFCore 是对 EntityFramework 的增强库,提供更多数据注解、数据库函数及自定义储存规则等。

https://github.com/zmjack/LinqSharp

由于内容较多,将分篇介绍公开内容、原理及案例分享:

  1. LinqSharp:简化复杂查询

  2. LinqSharp:动态构建 LINQ 查询

  3. LinqSharp.EFCore:表设计数据注解

  4. LinqSharp.EFCore:字段标准化数据注解

  5. LinqSharp.EFCore:函数映射

  6. LinqSharp.EFCore:列式存储代理

  7. LinqSharp.EFCore:关联计算与审计

本文多数示例,提供在线运行测试(.NET Fiddle)。


LinqSharp 为 LINQ 提供了以下增强(“内存查询”或“SQL生成”):

  • 默认返回方法
    MinOrDefault:提供默认返回的 Min 方法;
    MaxOrDefault:提供默认返回的 Max 方法;
    AverageOrDefault:提供默认返回的 Average 方法。

  • 查询值最小或最大的记录
    WhereMin:查询指定字段最小的记录;
    WhereMax:查询指定字段最大的记录。

  • 数据搜索
    Search:在指定字段或链接表字段中模糊或精确查询数据;

  • 分页查询
    SelectPage:查询结果分页或执行分页查询。

  • 序列排序
    OrderByCase / ThenByCase:按指定字符串序列排序。

  • 构建动态查询
    XWhere:构建动态查询。

以下方法仅提供于内存查询:

  • 按组元素数量分组
    GroupByCount:按分组记录元素数量分组。

  • 树结构查询
    SelectMore:按树结构遍历,选择“所有树节点中满足条件的节点”;
    SelectUntil:按树结构遍历,直到在每个子路径中找到满足条件的节点,选择该节点;
    SelectWhile:按树结构遍历,选择“所有子路径中连续满足条件的路径节点”。


示例库 Northwnd

Northwnd 是 SQL Server 早期附带的示例数据库,该数据库描述“公司销售产品网”简单案例场景。包括“雇员(Employees)”“产品订单(Orders)”“供应商(Suppliers)”的关系网络。

本文示例使用的是它的 Sqlite 版本(Code First):

https://github.com/zmjack/Northwnd

通过 NuGet 安装:

dotnet add package Northwnd
dotnet add package LinqSharp
dotnet add package LinqSharp.EFCore

简单使用:

using (var sqlite = NorthwndContext.UseSqliteResource())
{...
}

输出 SQL

“输出 SQL”是研究“SQL 生成”的基础,使用 LinqSharp.EFCore 中的 ToSql 方法:

(在线示例:ToSql | C# Online Compiler)

using (var sqlite = NorthwndContext.UseSqliteResource())
{var query = sqlite.Regions.Where(x => x.RegionDescription == "Northern");var sql = query.ToSql();
}

生成 SQL:

SELECT "r"."RegionID", "r"."RegionDescription"
FROM "Regions" AS "r"
WHERE "r"."RegionDescription" = 'Northern';

注1:由于不同版本的 EntityFrameworkCore 的 SQL 生成器设计不同,因此,生成 SQL 可能会存在差异。(EntityFrameworkCore 5.0 公开了 ToQueryString 来支持这项功能)。

注2:LinqSharp.EFCore 最新版本不兼容所有 EntityFrameworkCore,需使用“大版本号”与 EntityFrameworkCore 一致的发行库(例如,2.2.x,3.0.x,3.1.x)。

默认返回方法扩展

  • MinOrDefault:原函数 Min 的不抛异常版本,异常返回默认值;

  • MaxOrDefault:原函数 Max 的不抛异常版本,异常返回默认值;

  • AverageOrDefault:原函数 Average 的不抛异常版本,异常返回默认值。

(在线示例:MinOrDefault | C# Online Compiler)

// throw 'Sequence contains no elements'
new int[0].Min();new int[0].MinOrDefault();      // 0
new int[0].MinOrDefault(-1);    // -1

查询值最小或最大的记录

  • WhereMin:查询指定字段最小的记录;

  • WhereMax:查询指定字段最大的记录。

WhereMin 和 WhereMax 会进行两次查询:

  1. 查询指定字段的“最小值”或“最大值”;

  2. 查询指定字段“最小值”或“最大值”的记录。

例如,查询员工(Empolyees)表中年龄最小的员工:

(在线示例:WhereMax | C# Online Compiler)

var query = sqlite.Employees.WhereMax(x => x.BirthDate);
var result = query.Select(x => new
{x.EmployeeID,x.FirstName,x.BirthDate,
}).ToArray();

生成 SQL:

/* Step 1 */
SELECT MIN("e"."BirthDate")
FROM "Employees" AS "e";/* Step 2 */
SELECT *
FROM "Employees" AS "e"
WHERE "e"."BirthDate" = '1966-01-27 00:00:00';

运行结果:

数据搜索

  • Search:返回“从指定字段或外键表字段中进行模糊或精确查询”的查询结果。

Search 函数提供了四种搜索模式(SearchOption):

  • Contains(默认):任何指定字段中“包含”搜索字符串;

  • NotContains:所有指定字段中都“不包含”搜索字符串;

  • Equals:搜索字符串与某指定字段“相等”;

  • NotEquals:搜索字符串“不在”任何指定字段中。

例如,查询雇员(Employees)表中地址(Address)或城市(City)包含字母 m 的雇员:

(在线示例:Search | C# Online Compiler)

var query = sqlite.Employees.Search("m", e => new{e.Address,e.City,});
var result = query.Select(x => new
{x.EmployeeID,x.Address,x.City,
}).ToArray();

生成 SQL:

SELECT *
FROM "Employees" AS "e"
WHERE (('m' = '') OR (instr("e"."Address", 'm') > 0)) OR (('m' = '') OR (instr("e"."City", 'm') > 0));

运行结果:

Search 函数同样提供了外链表的查询(主表或从表查询)。

例如,查询供应商(Suppliers)表中供应任何种类豆腐(Tofu)的供应商:

(在线示例:Search (Details) | C# Online Compiler)

var query = sqlite.Suppliers.Include(x => x.Products).Search("Tofu", s => new{ProductNames = s.Products.Select(x => x.ProductName),});var result = query.Select(x => new
{x.SupplierID,x.CompanyName,Products = string.Join(", ", x.Products.Select(p => p.ProductName)),
}).ToArray();

生成 SQL:

SELECT *
FROM "Suppliers" AS "s"
LEFT JOIN "Products" AS "p" ON "s"."SupplierID" = "p"."SupplierID"
WHERE EXISTS (SELECT 1FROM "Products" AS "p0"WHERE ("s"."SupplierID" = "p0"."SupplierID") AND (('Tofu' = '') OR (instr("p0"."ProductName", 'Tofu') > 0)))
ORDER BY "s"."SupplierID", "p"."ProductID";

运行结果:

分页查询

  • SelectPage:查询结果分页或执行分页查询。(分页参数从第 1 页开始)

例如,查询雇员(Employees)表,按每页 2 条记录分页,选择第 3 页的记录返回:

(在线示例:SelectPage | C# Online Compiler)

var query = sqlite.Employees.SelectPage(pageNumber: 3, pageSize: 2);
var result = query.Select(x => new
{x.EmployeeID,x.Address,x.City,
}).ToArray();

生成 SQL:

SELECT *
FROM "Employees" AS "e"
ORDER BY (SELECT 1)
LIMIT 2 OFFSET 4;

运行结果:

序列排序

  • OrderByCase / ThenByCase:按指定字符串序列排序。

例如,查询地区(Regions)表,将结果按 N / E / W / S 的地区序列排序返回:

(在线示例:OrderByCase | C# Online Compiler)

var query = sqlite.Regions.OrderByCase(x => x.RegionDescription, new[]{"Northern","Eastern","Western","Southern",});
var result = query.Select(x => new
{x.RegionID,x.RegionDescription,
});

执行 SQL:

SELECT *
FROM "Regions" AS "r"
ORDER BY CASEWHEN "r"."RegionDescription" = 'Northern' THEN 0ELSE CASEWHEN "r"."RegionDescription" = 'Eastern' THEN 1ELSE CASEWHEN "r"."RegionDescription" = 'Western' THEN 2ELSE CASEWHEN "r"."RegionDescription" = 'Southern' THEN 3ELSE 4ENDENDEND
END;

运行结果:


按组元素数量分组

数量分组函数 GroupByCount 用于根据指定每组记录数量(每组最多允许 n 条记录)进行特殊分组。

例如,将如下指定字符串按每行 16 个字符分成多行:

var s = "0123456789ABCDEF0123456789ABCDEF".GroupByCount(16).Select(g => new string(g.ToArray()));
0123456789ABCDEF
0123456789ABCDEF

树结构查询

  • SelectMore:按树结构遍历,选择“树节点中 所有 满足条件的 节点”;

  • SelectUntil:按树结构遍历,直到 在每个子路径中找到满足条件的节点,选择 该节点;

  • SelectWhile:按树结构遍历,选择“所有子路径 中连续满足条件的 路径节点”。

例如,雇员(Employees)表按照 EmployeeID 和 ReportsTo 定义结构如下:

SelectMore

按树结构遍历,选择“树节点中 所有 满足条件的 节点”。

例如,查询由 2 号雇员 Andrew 领导的所有成员(2, 1, 3, 4, 5, 6, 7, 9, 8):

方法:使用 SelectMore 从根节点查找即可。

(在线示例:SelectMore | C# Online Compiler)

var employees = sqlite.Employees.Include(x => x.Superordinate).Include(x => x.Subordinates).ToArray();
var query = employees.Where(x => x.EmployeeID == 2).SelectMore(x => x.Subordinates);var result = query.Select(x => new
{x.EmployeeID,x.FirstName,x.ReportsTo,ReportsTo_ = x.Superordinate?.FirstName,
});

运行结果:

SelectUntil

按树结构遍历,直到 在每个子路径中找到满足条件的节点,选择 该节点。

例如,查询由 2 号雇员 Andrew 领导的所有基层员工(叶节点,1, 3, 6, 7, 9, 8):

方法:使用 SelectUntil 从根节点查找,直到节点 Subordinates 为空。

(在线示例:SelectUntil | C# Online Compiler)

var employees = sqlite.Employees.Include(x => x.Superordinate).Include(x => x.Subordinates).ToArray();
var query = employees.Where(x => x.EmployeeID == 2).SelectUntil(x => x.Subordinates, x => !x.Subordinates.Any());var result = query.Select(x => new 
{x.EmployeeID,x.FirstName,x.ReportsTo,ReportsTo_ = x.Superordinate?.FirstName,
});

运行结果:

SelectWhile

按树结构遍历,选择“所有子路径 中连续满足条件的 路径节点”。

例如,查询由 2 号雇员 Andrew 领导的所有非基层员工(非叶节点,2, 5):

方法:使用 SelectWhile 从根节点查找路径,直到节点 Subordinates 为空。

(在线示例:SelectWhile | C# Online Compiler)

var employees = sqlite.Employees.Include(x => x.Superordinate).Include(x => x.Subordinates).ToArray();
var query = employees.Where(x => x.EmployeeID == 2).SelectWhile(x => x.Subordinates, x => x.Subordinates.Any());var result = query.Select(x => new 
{x.EmployeeID,x.FirstName,Subordinates = string.Join(", ", x.Subordinates.SelectMore(s => s.Subordinates).Select(s => s.FirstName)),
});

运行结果:


下篇文章将介绍如何使用 LinqSharp “动态生成查询”,敬请关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/304251.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c#事件的发布-订阅模型_微信灰度测试订阅号付费功能,小米推出最便宜5G套餐,腾讯辟谣高管猝死赔钱事件,核心期刊发布十岁儿童文章,这就是今天的其他大新闻!...

今天是1月15日农历十二月廿一杭州又开始下雨了今天中午出个门我们这乡下打车排队能排到十几个。。。下面是今天的其他大新闻# 微信宣布:正灰度测试订阅号付费功能( IT之家 ) 1月15日消息,腾讯微信团队今日表示,目前微信灰度测试订阅号付费能力…

据说这篇总结覆盖了一般Python开发面试中可能会问到的大部分问题

原文标题:一名python web后端开发工程师的面试总结先介绍下我的情况通信背景,工作一年多不到两年。之前一直在做C的MFC软件界面开发工作。公司为某不景气的国企研究所。(喏,我的工作经验很水:1是方向不对;2…

理解C#泛型运作原理

前言我们都知道泛型在C#的重要性,泛型是OOP语言中三大特征的多态的最重要的体现,几乎泛型撑起了整个.NET框架,在讲泛型之前,我们可以抛出一个问题,我们现在需要一个可扩容的数组类,且满足所有类型&#xff…

游戏计算机的显示器,玩游戏用多大显示器好?聊聊电脑显示器多大尺寸合适

最近有多位网友在“电脑百事网”微信公众号中留言问到“显示器多大尺寸合适”、“玩游戏用多大显示器好”类似的相关问题。今天小编就来抽空解答一下,希望对有类似问题的网络朋友有所参考。电脑显示器多大尺寸合适Q:玩游戏用多大显示器好?A&a…

搭建基于域名的虚拟web主机

创建两个目录&#xff0c;分别存放accp和benet两个网站的网页文件<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />创建两个页面用以以后的测试因为我的主页写的是index.htm&#xff0c;在配置文件httpd.conf中没有这个引导页面&…

百度地图大数据告诉你一线城市真相

01 城市人口吸引力大PK&#xff01;2017年度城市人口吸引力指数排名▼划重点&#xff1a;1、第三列里的省会城市南昌、长春、乌鲁木齐、兰州、海口、呼和浩特、西宁是对人口的吸引力较弱。2、第二列里的贵阳、沈阳、哈尔滨、石家庄、福州、合肥、南宁、昆明对人口的吸引力尚可。…

微软开源Power Fx,基于Excel的低代码编程语言

喜欢就关注我们吧&#xff01;微软宣布推出新的开源编程语言 Power Fx&#xff0c;一种基于 Microsoft Excel 的低代码公式语言&#xff1b;将可以在整个 Microsoft Power Platform 中进行使用。该语言背后的动机是开发一些 Excel 用户熟悉的东西&#xff0c;以内容为中心而不是…

如何通过自学找到一份开发的工作?

01学习过程比较仔细的学习了《cprimer》&#xff0c;并对每个习题都自己写代码实现了一遍&#xff0c;包括稍微复杂一点的例子。认真读完了《effective c》&#xff0c;《effective stl》。比较仔细的学完了《数据结构与算法分析》&#xff0c;并把其中的每种数据结构和算法都用…

BeetleX使用bootstrap5开发SPA应用

在早期版本BeetleX.WebFamily只提供了vuejselement的集成&#xff0c;由于element只适合PC管理应用开发相对于移动应用适配则没这么方便。在新版本组件集成了bootstrap5可以更好地适配移动Web应用&#xff1b;同时也集成了Fontawesome和bootstrapIcons,这样在开发过程中使用字体…

Jupyter 常见可视化框架的选择

文末有福利&#xff01;对于以Python作为技术栈的数据科学工作者&#xff0c;Jupyter是不得不提的数据报告工具。可能对于R社区而言&#xff0c;鼎鼎大名的ggplot2是常见的可视化框架&#xff0c;而大家对于Python&#xff0c;以及Jupyter为核心的交互式报告的可个视化方案就并…

AOP(面向切面编程)大概了解一下

前言上一篇在聊MemoryCache的时候&#xff0c;用到了Autofac提供的拦截器进行面向切面编程&#xff0c;很明显能体会到其优势&#xff0c;既然涉及到了&#xff0c;那就趁热打铁&#xff0c;一起来探探面向切面编程。正文1. 概述在软件业&#xff0c;AOP为Aspect Oriented Prog…

机器学习三部曲

随着科技的发展&#xff0c;计算机对人类的生产活动和社会活动产生了极为重要的影响&#xff0c;同时以强大的生命力飞速发展着。目前计算机正广泛用于社会各个领域&#xff0c;并朝着微型化、网络化、智能化和巨型化的方向前进。说到智能化&#xff0c;大家最先想到的应该就是…

AntDesign Pro + .NET Core 实现基于JWT的登录认证

很多同学说AgileConfig的UI实在是太丑了。我想想也是的&#xff0c;本来这个项目是我自己使用的&#xff0c;一开始甚至连UI都没有&#xff0c;全靠手动在数据库里修改数据。后来加上了UI也是使用了老掉牙的bootstrap3做为基础样式。前台框架也是使用了angularjs&#xff0c;同…

武汉大学计算机学院2019考研复试,2019年武汉大学硕士研究生复试及录取名单汇总...

原标题&#xff1a;2019年武汉大学硕士研究生复试及录取名单汇总考生可以通过录取名单了解到很多重要的信息&#xff0c;例如复试比例&#xff0c;进复试最低分&#xff0c;复试录取成绩&#xff0c;录取总评成绩等重要信息。以下是我们整理收集到的各学院复试录取名单汇总&…

ugui unity 取消选择_UGUI中几种不规则按钮的实现方式

前言UGUI中的按钮默认是矩形的&#xff0c;若要实现非矩形按钮该怎么做呢&#xff1f;比如这样的按钮&#xff1a;本文将介绍两种实现方式供大家选择。使用alphaHitTestMinimumThresholdImage类的alphaHitTestMinimumThreshold是一个浮点值&#xff0c;Raycast检测时只有图片中…

你的专业 VS 你妈口中你的专业

亲妈认证★英语语言文学我妈&#xff1a;她就是一个学英语的~我同学&#xff1a;你学英语的啊&#xff1f;那你看美剧不用看字幕的吧&#xff1f;你听英文歌都听得懂的吧&#xff1f;这个怎么翻译啊&#xff1f;这上面写的什么&#xff1f;你不是专八吗&#xff1f;哈喽~ 在吗&…

反射 + 抽象工厂模式切换不同的实现方法

概述工厂模式&#xff08;Abstract Factory&#xff09;定义 &#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是围绕一个超级工厂创建其他工厂。该超级工厂又称为其…

3 年工作经验程序员应有的技能

前言因为和同事有约定再加上LZ自己也喜欢做完一件事之后进行总结&#xff0c;因此有了这篇文章。这篇文章大部分内容都是面向整个程序员群体的&#xff0c;当然因为LZ本身是做Java开发的&#xff0c;因此有一部分内容也是专门面向咱们Java程序员的。第二阶段&#xff1a;五年五…

应急响应中的溯源方法

在发现有入侵者后&#xff0c;快速由守转攻&#xff0c;进行精准地溯源反制&#xff0c;收集攻击路径和攻击者身份信息&#xff0c;勾勒出完整的攻击者画像。 对内溯源与对内溯源 对内溯源&#xff1a;确认攻击者的行为 &#xff0c;分析日志 数据包等&#xff1b; 对外溯源&…

POP3口令扫描案例

通过本案例可以学到&#xff1a; (1)了解POP3有关知识(2)利用Hscan工具软件来破解POP3账号和口令现在很多邮箱服务器都支持POP3功能&#xff0c;通过POP3来收取信件&#xff0c;收取信件时仅仅需要提供用户名和密码。目前有很多工具可以扫描POP3邮件账号和口令&#xff0c;本案…