为了提高开发者的易用性,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. 总结Objective-c常用算法

          今天是星期天,想睡到10点起床,结果认为自己太奢侈了,不能这么做,于是把闹钟设置成了6:30:结果终于9:36醒了,起床,无缘无故迟了,好吧,就算太累了吧,周天就原谅自己一回.终于到了中午 ...

  2. .NET垃圾回收(GC)原理

    作为.NET进阶内容的一部分,垃圾回收器(简称GC)是必须了解的内容.本着“通俗易懂”的原则,本文将解释CLR中垃圾回收器的工作原理. 基础知识 托管堆(Managed Heap) 先来看MSDN的解 ...

  3. [ASP.NET MVC 小牛之路]03 - Razor语法

    本人博客已转移至:http://www.exblr.com/liam  Razor是MVC3中才有的新的视图引擎.我们知道,在ASP.NET中,ASPX的视图引擎依靠<%和%>来调用C#指 ...

  4. JVM系列-分代收集垃圾回收

    Java自动垃圾回收(Automatic Garbage Collection)是自动回收堆上不再使用的内存,new的对象在程序中没有引用指向它,就会被回收.回收的实现很多,有Reference Co ...

  5. weblogic配置数据源

    启动weblogic 管理服务器,使用管理用户登录weblogic管理控制台   打开管理控制台后,在左侧的树形域结构中,选择服务->数据源. 在右侧的窗口中,选择 新建->一般数据源   ...

  6. 推荐两款简单好用的图片放大jquery插件

    一.zoomfiy.js 推荐可以从这里下载 使用说明: 使用该jquery 插件引入该插件的js:zoomfiy.js 或 min引入该插件的css:zoomfiy.css 或 min前后顺序都可j ...

  7. SQL注入

    @org.junit.Test public void testLogin() { CardDAO cd=new CardDAO(); if(cd.dengru("' or 1 = 1--& ...

  8. HTML5系列:HTML5表单

    1. input元素新增类型 url类型 url类型的input元素是一种用来输入url的文本框,提交时如果该文本框中内容不是url格式,则不允许提交. <input type="ur ...

  9. CSS系列:CSS中盒子的浮动与定位

    1. 盒子的浮动 在标准流中,一个块级元素在水平方向会自动伸展,知道包含它的元素的边接:而在竖直方向与相邻元素依次排列,不能并排. CSS中float属性,默认为none.将float属性的值设置为l ...

  10. ASP.NET MVC5 网站开发实践(一) - 项目框架

    前几天算是开题了,关于怎么做自己想了很多,但毕竟没做过项目既不知道这些想法有无必要,也不知道能不能实现,不过邓爷爷说过"摸着石头过河"吧.这段时间看了一些博主的文章收获很大,特别是 ...