本文介绍如何使用 Rafy 框架中的 Sql Tree 查询:
除了开发者常用的 Linq 查询,Rafy 框架还提供了 Sql 语法树的方式来进行查询。
这种查询方式下,开发者不需要直接编写真正的 Sql 语句,而是转而使用一套中间 Sql 语法树对象。这隔离了与具体数据库的耦合,使得开发者编写的查询可以跨越多种不同的数据库运行,甚至可以在非关系型数据库中运行。同时,框架还结合托管属性,提供了方便开发者使用的 API,并尽量保持与传统 Sql 相近的语法,使得开发者可以快速理解并编写。
本文包含以下章节:
快速示例
SqlTree 查询是直接以一种类似于 Sql 语法的格式,并结合实体托管属性 IManagedProperty 来进行查询的查询模式。如下:
[RepositoryQuery]
public virtual ChapterList GetBy(string name, PagingInfo pi)
{
var f = QueryFactory.Instance;
var t = f.Table<Chapter>();
var q = f.Query(
selection: f.SelectAll(),//查询所有列
from: t,//要查询的实体的表
where: t.Column(Chapter.NameProperty).Contains(name)//where 条件,
orderBy: new List<IOrderBy> {//排序
f.OrderBy(source.Column(Chapter.NameProperty), OrderDirection.Ascending)
}
);
return (ChapterList)this.QueryData(q, pi);
}
可以看到,SqlTree 语法非常简单:
更多的查询语法示例,见本节后面的更多示例。
使用场景
当您处于以下场景时,需要使用 SqlTree 查询:
代码段
RafySDK 中提供了两个代码段,来辅助开发者生成基本的 SqlTree 查询结构:Rafy_Query、Rafy_Query_TableQueryContent。
详情见:代码段。
更多示例
下面将会列出一些常见的 SqlTree 查询示例。通过这些代码,您将学习到如何在各种查询需求下使用 SqlTree。
基础查询:
[RepositoryQuery]
public virtual ChapterList GetBy(string name, PagingInfo pi)
{
var f = QueryFactory.Instance;
var t = f.Table<Chapter>();
var q = f.Query(
//selection: f.SelectAll(),//没有 selection,则默认表示查询所有列
from: t,//要查询的实体的表
where: t.Column(Chapter.NameProperty).Contains(name)//where 条件
);
return (ChapterList)this.QueryData(q, pi);
}
表格数据查询:
[RepositoryQuery]
public virtual LiteDataTable GetBy(string name, PagingInfo pi)
{
var f = QueryFactory.Instance;
var t = f.Table<Chapter>();
var q = f.Query(
from: t,
where: t.Column(Chapter.NameProperty).Contains(name)
);
return this.QueryTable(q, pi);//由查询实体变为查询数据表格,只是更换了这一行代码。
}两个列的条件进行比较:
var table = f.Table(this);//使用当前的仓库来表示当前的表
var q = f.Query(
from :table,
where: table.Column(Chapter.NameProperty).Equal(table.Column(Chapter.CodeProperty))//两个列相等
);使用 And、Or:
var table = f.Table(this);
var q = f.Query(
from :table,
where: f.And(
table.Column(Chapter.NameProperty).Equal(name),
f.Or(
table.Column(Chapter.IdProperty).LessEqual(10),
table.Column(Chapter.IdProperty).GreaterEqual(1000)
)
)
);
Join(SerialNumberValueRepository 中的真实代码):
/// <summary>
/// 获取某个规则下最新的一个值。
/// </summary>
/// <param name="autoCodeName"></param>
/// <returns></returns>
[RepositoryQuery]
public virtual SerialNumberValue GetLastValue(string autoCodeName)
{
var f = QueryFactory.Instance;
var t = f.Table<SerialNumberValue>();
var t2 = f.Table<SerialNumberInfo>();
var q = f.Query(
from: t.Join(t2),//由于 SerialNumberValue 有一个 SerialNumberInfo 的引用属性,则在使用 Join 时,不需要给出 Join 的条件。
where: t2.Column(SerialNumberInfo.NameProperty).Equal(autoCodeName),
orderBy: new List<IOrderBy> { f.OrderBy(t.Column(SerialNumberValue.LastUpdatedTimeProperty), OrderDirection.Descending) }
);
return (SerialNumberValue)this.QueryData(q);
}
使用完整的 Join:
var t = f.Table<SerialNumberValue>();
var t2 = f.Table<SerialNumberInfo>();
var q = f.Query(
from: t.Join(t2, t.Column(SerialNumberValue.SerialNumberInfoIdProperty).Equal(t2.Column(SerialNumberInfo.IdProperty)), JoinType.Inner),//不但可以给出具体的 Join 条件,还可以给出 Join 类型。
where: t2.Column(SerialNumberInfo.NameProperty).Equal(autoCodeName),
orderBy: new List<IOrderBy> { f.OrderBy(t.Column(SerialNumberValue.LastUpdatedTimeProperty), OrderDirection.Descending) }
);
Exists:
var bookTable = f.Table(this);
var chapterTable = f.Table<Chapter>();
var q = f.Query(
from: bookTable,
where: f.Exists(f.Query(
from: chapterTable,
where: chapterTable.Column(Chapter.BookIdProperty).Equal(bookTable.IdColumn)
))
);
Not Exists:
var book = f.Table(this);
var chapter = f.Table<Chapter>();
var q = f.Query(
from: book,
where: f.Not(f.Exists(f.Query(
from: chapter,
where: f.And(
f.Constraint(chapter.Column(Chapter.BookIdProperty), book.IdColumn),
f.Constraint(chapter.Column(Chapter.NameProperty), PropertyOperator.NotEqual, chapterName)
)
)))
);
更多示例,请参照源码中单元测试的 ORMTest 中的 TableQuery 相关方法。
PS:该文已经纳入《 Rafy 用户手册》中。