.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日消息,腾讯微信团队今日表示,目前微信灰度测试订阅号付费能力…

计算机组成原理第04章在线测试,计算机组成原理第四章单元测试(二)(含答案).docx...

PAGEPAGE 1第四章存储系统(二)测试书生1、32位处理器的最大虚拟地址空间为????A、2G????B、4G????C、8G????D、16G2、在虚存、内存之间进行地址变换时,功能部件 ( )将地址从虚拟(逻辑)地址空间映射到物理地址空间????A、TLB????B、MMU???…

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

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

理解C#泛型运作原理

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

visio软件接口流程图_Microsoft Office Visio绘制系统框图以及流程图的操作步骤

最近很多朋友咨询关于Microsoft OfficeVisio如何绘制系统框图以及流程图的问题,今天的这篇教程就来聊一聊这个话题,希望可以帮助到有需要的朋友。Microsoft Office Visio绘制系统框图以及流程图的操作步骤我们先在桌面空白处或文件夹下,点击鼠…

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

最近有多位网友在“电脑百事网”微信公众号中留言问到“显示器多大尺寸合适”、“玩游戏用多大显示器好”类似的相关问题。今天小编就来抽空解答一下,希望对有类似问题的网络朋友有所参考。电脑显示器多大尺寸合适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;以内容为中心而不是…

python浅拷贝_Python中的浅拷贝和深拷贝

本文翻译自copy in Python (Deep Copy and Shallow Copy)&#xff0c;讲述了在Python语言中浅拷贝与深拷贝的不同用法。全文系作者原创&#xff0c;仅供学习参考使用&#xff0c;转载授权请私信联系&#xff0c;否则将视为侵权行为。码字不易&#xff0c;感谢支持。以下为全文内…

常用计算机二级函数,计算机二级MS office常用函数

计算机二级MS office常用函数1、DAVERAGE用途&#xff1a;返回数据库或数据清单中满足指定条件的列中数值的平均值。语法&#xff1a;DAVERAGE(database&#xff0c;field&#xff0c;criteria)参数&#xff1a;Database 构成列表或数据库的单元格区域;Field指定函数所使用的数…

错误删除linux分区致Win7引导失败的修复方法

以前在Winxp和linux双启动时&#xff0c;若完全 删除了linux分区&#xff0c;重启进不了Winxp时&#xff0c;只需要用Winxp的光盘引导系统到命令行或故障恢复控制台&#xff0c;输入fixmbr和fixboot即可解决。现在是win7系统&#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,这样在开发过程中使用字体…

计算机基础知识菜鸟教程,机器学习基础知识整理归纳

关于机器学习的一些基本概念的整理1.前言1.机器学习是一门致力于研究如何通过计算的手段&#xff0c;利用经验来改善系统自身的性能的学科。1997年Mitchell给出一个更形式化的定义&#xff0c;假设用P来评估计算机程序在某任务类T上的性能&#xff0c;若一个程序通过利用经验E在…

python echo函数_python如何调用php文件中的函数详解

前言python调用php代码实现思路&#xff1a;php文件可通过在terminal中使用php命令行进行调用&#xff0c;因此可使用python开启子进程执行命令行代码。函数所需的参数可通过命令行传递。测试环境1、操作系统&#xff1a;macos10.13.22、php版本&#xff1a;PHP 7.1.7(mac自带)…

今天换了ubuntu10.04

今天换成了ubuntu10.04&#xff0c;开机很快&#xff0c;17秒到登录界面&#xff0c;在我这台dell vostro 1500上很快很快了。快是ubuntu10.04给我的第一印象。至于界面什么的&#xff0c;我真觉得没什么区别&#xff0c;反正我也不开特效&#xff0c;管它呢&#xff01;反正我…

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…

es6添加删除class_es6中class类的使用

在es5中我们是使用构造函数实例化出来一个对象&#xff0c;那么构造函数与普通的函数有什么区别呢&#xff1f;其实没有区别&#xff0c;无非就是函数名称用首字母大写来加以区分&#xff0c;这个不用对说对es5有了解的朋友都应该知道。但是es5的这种方式给人的感觉还是不够严谨…