为了提高开发者的易用性,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 查询支持(根据聚合子条件查询聚合父)的更多相关文章

  1. query_string查询支持全部的Apache Lucene查询语法 低频词划分依据 模糊查询 Disjunction Max

    3.3 基本查询3.3.1词条查询 词条查询是未经分析的,要跟索引文档中的词条完全匹配注意:在输入数据中,title字段含有Crime and Punishment,但我们使用小写开头的crime来搜 ...

  2. SEC6 - MySQL 查询语句--------------进阶2:条件查询

    # 进阶2:条件查询 /* 语法: select 查询列表 from 表名 where 筛选条件; 分类: 一.按照条件表达式筛选 条件运算符:> < = !=(等价于<>) ...

  3. 高级查询子条件查询filter

    Filter Context 在查询过程中,只判断该文档是否满足条件,只有Yes或者No { "query":{ "bool":{ //布尔关键词 " ...

  4. 基于Solr的HBase多条件查询测试

    背景: 某电信项目中采用HBase来存储用户终端明细数据,供前台页面即时查询.HBase无可置疑拥有其优势,但其本身只对rowkey支持毫秒级 的快 速检索,对于多字段的组合查询却无能为力.针对HBa ...

  5. thinkphp where()条件查询

    今天来给大家讲下查询最常用但也是最复杂的where方法,where方法也属于模型类的连贯操作方法之一,主要用于查询和操作条件的设置.where方法的用法是ThinkPHP查询语言的精髓,也是Think ...

  6. Spring MVC和Spring Data JPA之按条件查询和分页(kkpaper分页组件)

    推荐视频:尚硅谷Spring Data JPA视频教程,一学就会,百度一下就有, 后台代码:在DAO层继承Spring Data JPA的PagingAndSortingRepository接口实现的 ...

  7. 2017.2.21 activiti实战--第十三章--流量数据查询与跟踪(一)查询接口介绍及运行时数据查询

    学习资料:<Activiti实战> 第十三章 流量数据查询与跟踪 本章讲解运行时与历史数据的查询方法.主要包含三种:标准查询,Native查询,CustomSql查询. 13.1 Quer ...

  8. EasyUI ComboGrid的绑定,上下键和回车事件,输入条件查询

    首先我们先看一下前台的绑定事件 1.先定义标签 <input id="cmbXm" type="text" style="width: 100p ...

  9. WebFrom 小程序【条件查询】

    实现按照各种条件对数据库进行综合查询 基本功能:可以根据用户需要灵活查询 重难点:各种条件的可能.限制. public List<users> selectA( string str,Ha ...

随机推荐

  1. 建模元件有哪些在MapleSim中

    信号库:包含通用信号模块.布尔.控制器.离散信号模块.信号源.线性信号模块.非线性信号模块.时间离散信号模块.查询表.信号转换器.数学运算.关系元件.特殊信号模块,应用案例. 电子库:包含电阻.运算放 ...

  2. 你的应用是如何被替换的,App劫持病毒剖析

    一.App劫持病毒介绍 App劫持是指执行流程被重定向,又可分为Activity劫持.安装劫持.流量劫持.函数执行劫持等.本文将对近期利用Acticity劫持和安装劫持的病毒进行分析. 二.Activ ...

  3. jQuery.Callbacks之demo

    jQuery.Callbacks是jquery在1.7版本之后加入的,是从1.6版中的_Deferred对象中抽离的,主要用来进行函数队列的add.remove.fire.lock等操作,并提供onc ...

  4. C++高精度计时器——微秒级时间统计

    在C++中,经常需要通过计时来统计性能信息,通过统计的耗时信息,来分析性能瓶颈,通常情况下,可能毫秒级别的时间统计就足够用了,但是在毫厘必争的性能热点的地方,毫秒级别的统计还是不够的,这种情况下,就需 ...

  5. Jenkins常用插件说明(持续更新)

    本文主要记录在学习以及使用Jenkins过程中常用的对我们有帮助的插件,同时本文将会持续进行更新.如果大家发现有其他野很好用的插件,也欢迎参照下面的格式,在评论中进行回复反馈. 一.通用插件 1.Em ...

  6. Outlook HTML渲染引擎

    OutLook始终不离不弃 是不是很讨厌为Email代码兼容Outlook? 太遗憾了!虽然光都有尽头,但Outlook始终存在. 为了应付Email的怪癖,我们花了很多时间测试,确保我们搞定了所有O ...

  7. Java中常见的29个运行异常

    ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotR ...

  8. 【hadoop摸索系列】记录使用libhdfs访问hdfs的关键问题

    hadoop官方的二进制发布版本一直是32位平台编译的,对于java来说跨平台不影响使用,但是为了在c/c++程序中操作hdfs就做不到了,因为libhdfs.so是二进制不兼容的. 我使用的是sta ...

  9. MacOS中使用QT开发iOS应用

    因为项目合同中规定一部分业务内容要在手机端实现,包括安卓机和苹果机,因此选择了QT作为开发工具.程序在Win10和安卓系统上已经完美运行,这几天开始搭建iOS的编译和发布环境,因为以前没有使用过mac ...

  10. 用bootstrap实现多张图片手动轮回

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABBoAAAJoCAIAAABHhBX4AAAgAElEQVR4nOzdZXdcV7rg8fmIM2vm3r