Rafy 中的 Linq 查询支持(根据聚合子条件查询聚合父)
为了提高开发者的易用性,Rafy 领域实体框架在很早开始就已经支持使用 Linq 语法来查询实体了。但是只支持了一些简单的、常用的条件查询,支持的力度很有限。特别是遇到对聚合对象的查询时,就不能再使用 Linq,而只能通过构造底层查询树的接口来完成了。由于开发者的聚合查询的需求越来越多,所以本周我们将这部分进行了增强。
接下来,本文将说明 Rafy 框架原来支持的 Linq 语法,以及最新加入的聚合查询支持及用法。
使用 Linq 查询的代码示例
public WarehouseList GetByCode(string warehouseCode, string nameKeywords, PagingInfo pagingInfo)
{
return this.FetchList(r => r.DA_GetByCode(warehouseCode, nameKeywords, pagingInfo));
}
private EntityList DA_GetByCode(string warehouseCode, string nameKeywords, PagingInfo pagingInfo)
{
var q = this.CreateLinqQuery();
//条件对比
q = q.Where(e => e.Code == warehouseCode);
if (!string.IsNullOrEmpty(nameKeywords))
{
q = q.Where(e => e.Name.Contains(nameKeywords));
}
//排序
q = q.OrderByDescending(w => w.Name);
return this.QueryList(q, pagingInfo);//以指定的分页信息 pagingInfo 分页
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
支持的一般查询
使用 CreateLinqQuery 方法创建出一个 IQueryable<Warehouse> 对象,针对该对象,我们可以以下的标准 Linq 方法:Where、OrderBy、OrderByDescending、ThenBy、ThenByDescending、Count。
对于其中最重要的 Where 方法,Rafy 也支持许多操作,包括:
- 属性的各种对比操作(=,!=,>,>=,<,<=,!,Contains,StartsWith,EndsWith等)。
- 支持两个属性条件间的连接条件:&&、||。
- 支持引用查询。即间接使用引用实体的属性来进行查询,在生成 Sql 语句时,将会生成 INNER JOIN 语句,连接上这些被使用的引用实体对应的表。例如:
q = q.Where(warehouse => warehouse.Administrator.Name == "admin");
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
这部分的内容,之前的版本已经支持了,各位可参见 Rafy 框架的用户手册。
聚合查询
聚合查询的功能是,开发者可以通过定义聚合子的属性的条件,来查询聚合父。这是本次升级的重点。
例如,书籍管理系统中,Book (书)为聚合根,它拥有 Chapter (章)作为它的聚合子实体,而 Chapter 下则还有 Section(节)。那么,我们可以通过这个功能,来查询类似以下需求的数据:
- 查询拥有某个章的名字的所有书籍。
要实现这种场景的查询,我们可以在仓库的数据层,使用下面的 Linq 语法:
public BookList LinqGetIfChildrenExists(string chapterName)
{
return this.FetchList(r => r.DA_LinqGetIfChildrenExists(chapterName));
}
private EntityList DA_LinqGetIfChildrenExists(string chapterName)
{
var q = this.CreateLinqQuery();
q = q.Where(book => book.ChapterList.Concrete().Any(c => c.Name == chapterName));
q = q.OrderBy(b => b.Name);
return this.QueryList(q);
}
其生成的 Sql 如下:
SELECT [T0].[Id], [T0].[Author], [T0].[BookCategoryId], [T0].[BookLocId], [T0].[Code], [T0].[Name], [T0].[Price], [T0].[Publisher]
FROM [Book] AS [T0]
WHERE EXISTS (
SELECT 1
FROM [Chapter] AS [T1]
WHERE [T1].[BookId] = [T0].[Id] AND [T1].[Name] = @p0
)
ORDER BY [T0].[Name] ASC
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
- 查询每个章的名字必须满足某条件的所有书籍。
我们可以在仓库的数据层,使用下面的 Linq 语法:
public BookList LinqGetIfChildrenAll(string chapterName)
{
return this.FetchList(r => r.DA_LinqGetIfChildrenAll(chapterName));
}
private EntityList DA_LinqGetIfChildrenAll(string chapterName)
{
var q = this.CreateLinqQuery();
q = q.Where(e => e.ChapterList.Cast<Chapter>().All(c => c.Name == chapterName));
q = q.OrderBy(e => e.Name);
return this.QueryList(q);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }生成的 SQL 是:
SELECT [T0].[Id], [T0].[Author], [T0].[BookCategoryId], [T0].[BookLocId], [T0].[Code], [T0].[Name], [T0].[Price], [T0].[Publisher]
FROM [Book] AS [T0]
WHERE NOT (EXISTS (
SELECT 1
FROM [Chapter] AS [T1]
WHERE [T1].[BookId] = [T0].[Id] AND [T1].[Name] != @p0
))
ORDER BY [T0].[Name] ASC
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
- 查询某个章中所有节必须满足某条件的所有书籍。
我们可以在仓库的数据层,使用下面的 Linq 语法:
public BookList LinqGetIfChildrenExistsSectionName(string sectionName)
{
return this.FetchList(r => r.DA_LinqGetIfChildrenExistsSectionName(sectionName));
}
private EntityList DA_LinqGetIfChildrenExistsSectionName(string sectionName)
{
var q = this.CreateLinqQuery();
q = q.Where(book => book.ChapterList.Concrete().Any(c => c.SectionList.Cast<Section>().Any(s => s.Name.Contains(sectionName))));
q = q.OrderBy(b => b.Name);
return this.QueryList(q);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
将会生成如下 SQL:
SELECT [T0].[Id], [T0].[Author], [T0].[BookCategoryId], [T0].[BookLocId], [T0].[Code], [T0].[Name], [T0].[Price], [T0].[Publisher]
FROM [Book] AS [T0]
WHERE EXISTS (
SELECT 1
FROM [Chapter] AS [T1]
WHERE [T1].[BookId] = [T0].[Id] AND EXISTS (
SELECT 1
FROM [Section] AS [T2]
WHERE [T2].[ChapterId] = [T1].[Id] AND [T2].[Name] LIKE @p0
)
)
ORDER BY [T0].[Name] ASC
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
- 同时,这些查询也可以支持分页。例如,我们在上面的查询添加一个分页条件,代码如下:
public BookList LinqGetIfChildrenExistsSectionName(string sectionName)
{
return this.FetchList(r => r.DA_LinqGetIfChildrenExistsSectionName(sectionName));
}
private EntityList DA_LinqGetIfChildrenExistsSectionName(string sectionName)
{
var q = this.CreateLinqQuery();
q = q.Where(book => book.ChapterList.Concrete().Any(c => c.SectionList.Cast<Section>().Any(s => s.Name.Contains(sectionName))));
q = q.OrderBy(b => b.Name);
return this.QueryList(q, new PagingInfo(2, 1));//分页
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
分成的 SQL 如下:
SELECT TOP 1 [T0].[Id], [T0].[Author], [T0].[BookCategoryId], [T0].[BookLocId], [T0].[Code], [T0].[Name], [T0].[Price], [T0].[Publisher]
FROM [Book] AS [T0]
WHERE EXISTS (
SELECT 1
FROM [Chapter] AS [T1]
WHERE [T1].[BookId] = [T0].[Id] AND EXISTS (
SELECT 1
FROM [Section] AS [T2]
WHERE [T2].[ChapterId] = [T1].[Id] AND [T2].[Name] LIKE @p0
)
) AND [T0].[Id] NOT IN (
SELECT TOP 1 [T0].[Id]
FROM [Book] AS [T0]
WHERE EXISTS (
SELECT 1
FROM [Chapter] AS [T1]
WHERE [T1].[BookId] = [T0].[Id] AND EXISTS (
SELECT 1
FROM [Section] AS [T2]
WHERE [T2].[ChapterId] = [T1].[Id] AND [T2].[Name] LIKE @p1
)
)
ORDER BY [T0].[Name] ASC
)
ORDER BY [T0].[Name] ASC
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
头晕,越来越复杂……不过经过测试,上面都没有什么问题。
下面是一个单元测试生成的分页、复杂聚合查询的 SQL,贴上来观赏下:
SELECT TOP 2 [T0].[Id], [T0].[Author], [T0].[BookCategoryId], [T0].[BookLocId], [T0].[Code], [T0].[Name], [T0].[Price], [T0].[Publisher]
FROM [Book] AS [T0]
LEFT OUTER JOIN [BookCategory] AS [T1] ON [T0].[BookCategoryId] = [T1].[Id]
WHERE [T0].[Name] != @p0 AND [T1].[Name] = @p1 AND EXISTS (
SELECT 1
FROM [Chapter] AS [T2]
WHERE [T2].[BookId] = [T0].[Id] AND [T2].[Name] = @p2
) AND EXISTS (
SELECT 1
FROM [Chapter] AS [T3]
WHERE [T3].[BookId] = [T0].[Id] AND [T3].[Name] = @p3 AND NOT (EXISTS (
SELECT 1
FROM [Section] AS [T4]
LEFT OUTER JOIN [SectionOwner] AS [T5] ON [T4].[SectionOwnerId] = [T5].[Id]
WHERE [T4].[ChapterId] = [T3].[Id] AND ([T4].[Name] NOT LIKE @p4 OR [T4].[SectionOwnerId] IS NULL OR [T5].[Name] != @p5)
))
) AND [T0].[Id] NOT IN (
SELECT TOP 4 [T0].[Id]
FROM [Book] AS [T0]
LEFT OUTER JOIN [BookCategory] AS [T1] ON [T0].[BookCategoryId] = [T1].[Id]
WHERE [T0].[Name] != @p6 AND [T1].[Name] = @p7 AND EXISTS (
SELECT 1
FROM [Chapter] AS [T2]
WHERE [T2].[BookId] = [T0].[Id] AND [T2].[Name] = @p8
) AND EXISTS (
SELECT 1
FROM [Chapter] AS [T3]
WHERE [T3].[BookId] = [T0].[Id] AND [T3].[Name] = @p9 AND NOT (EXISTS (
SELECT 1
FROM [Section] AS [T4]
LEFT OUTER JOIN [SectionOwner] AS [T5] ON [T4].[SectionOwnerId] = [T5].[Id]
WHERE [T4].[ChapterId] = [T3].[Id] AND ([T4].[Name] NOT LIKE @p10 OR [T4].[SectionOwnerId] IS NULL OR [T5].[Name] != @p11)
))
)
ORDER BY [T0].[Name] ASC
)
ORDER BY [T0].[Name] ASC
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
刚开始支持 Linq 查询的时候,就已经把聚合查询的单元测试给写了。鉴于比较复杂,所以一直没有实现。这周总算完成了这部分代码,心中一块石头落了地。
Rafy 中的 Linq 查询支持(根据聚合子条件查询聚合父)的更多相关文章
- query_string查询支持全部的Apache Lucene查询语法 低频词划分依据 模糊查询 Disjunction Max
3.3 基本查询3.3.1词条查询 词条查询是未经分析的,要跟索引文档中的词条完全匹配注意:在输入数据中,title字段含有Crime and Punishment,但我们使用小写开头的crime来搜 ...
- SEC6 - MySQL 查询语句--------------进阶2:条件查询
# 进阶2:条件查询 /* 语法: select 查询列表 from 表名 where 筛选条件; 分类: 一.按照条件表达式筛选 条件运算符:> < = !=(等价于<>) ...
- 高级查询子条件查询filter
Filter Context 在查询过程中,只判断该文档是否满足条件,只有Yes或者No { "query":{ "bool":{ //布尔关键词 " ...
- 基于Solr的HBase多条件查询测试
背景: 某电信项目中采用HBase来存储用户终端明细数据,供前台页面即时查询.HBase无可置疑拥有其优势,但其本身只对rowkey支持毫秒级 的快 速检索,对于多字段的组合查询却无能为力.针对HBa ...
- thinkphp where()条件查询
今天来给大家讲下查询最常用但也是最复杂的where方法,where方法也属于模型类的连贯操作方法之一,主要用于查询和操作条件的设置.where方法的用法是ThinkPHP查询语言的精髓,也是Think ...
- Spring MVC和Spring Data JPA之按条件查询和分页(kkpaper分页组件)
推荐视频:尚硅谷Spring Data JPA视频教程,一学就会,百度一下就有, 后台代码:在DAO层继承Spring Data JPA的PagingAndSortingRepository接口实现的 ...
- 2017.2.21 activiti实战--第十三章--流量数据查询与跟踪(一)查询接口介绍及运行时数据查询
学习资料:<Activiti实战> 第十三章 流量数据查询与跟踪 本章讲解运行时与历史数据的查询方法.主要包含三种:标准查询,Native查询,CustomSql查询. 13.1 Quer ...
- EasyUI ComboGrid的绑定,上下键和回车事件,输入条件查询
首先我们先看一下前台的绑定事件 1.先定义标签 <input id="cmbXm" type="text" style="width: 100p ...
- WebFrom 小程序【条件查询】
实现按照各种条件对数据库进行综合查询 基本功能:可以根据用户需要灵活查询 重难点:各种条件的可能.限制. public List<users> selectA( string str,Ha ...
随机推荐
- Response.StatusCode的HTTP状态代码列表
1xx - 信息提示这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应. · 100 - Continue 初始的请求已经接受,客户应当继续发送请求的其余部分.( ...
- java.lang.IndexOutOfBoundsException at java.io.FileOutputStream.writeBytes(Native Method)
ss available : /usr/linkapp/data/linkapp/ddn_1440639847758_temp java.lang.IndexOutOfBoundsException ...
- JavaScript字符串排序localeCompare()笔记
今天遇到了一个没有接触过的方法,是localeCompare().查了一些相关的文档,给出的定义很模糊,所以就把自己的理解写下来. 首先由例子入手! 已知一串学生姓名的字符串,根据学生姓名的长度按照降 ...
- @OutputCache 详解-文章目录
OutputCache概念学习 OutputCache属性详解(一)一Duration.VaryByParam OutputCache属性详解(二)一 Location OutputCache属性详解 ...
- selenium的安装
一.安装selenium 通过pip命令安装selenium包:(pip的安装方法:http://www.cnblogs.com/zhengyihan1216/articles/6011640.htm ...
- jdk1.7.0_80源码包结构
解压源码src.zip,jdk源码结构如下所示: src |--com.sun sun公司对jdk的实现,Oracle官方不支持,不保证跨平台(可能一些类linux有而windows没有),甚至 ...
- Trace1:Default Trace
sql server trace 是一个轻量级的追踪工具,对追踪数据库的行为很有用,因此,sql server内置一个trace(default trace). 1,sql server 内置Defa ...
- 【.NET深呼吸】存储基于本地线程的值
在特定情况,我们希望这样一个场景: N个线程同时调用同一个类实例的同一个操作方法,并且同一个变量可以面向每一个线程存储独立的值.比如,某变量X,它对于线程A的值与对于线程B的值是相互独立的.线程A设置 ...
- 【转】WPF: 自动设置Owner的ShowDialog 适用于MVVM
原文地址:http://www.mgenware.com/blog/?p=339 WPF中的Windows的ShowDialog方法并没有提供设置Owner的参数,开发者需要在ShowDialog前设 ...
- Android中activity背景色的设置
Android应用开发——系统自带样式Android:theme •android:theme="@android:style/Theme.Dialog" 将一个Activit ...