C# Lambda 表达式生成 SQL 查询语句_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > C# Lambda 表达式生成 SQL 查询语句

C# Lambda 表达式生成 SQL 查询语句

 2017/10/26 14:55:45  丶最终幻想丶  程序员俱乐部  我要评论(0)
  • 摘要:由于一些历史原因,导致公司现有项目的数据库中存在大量中文表名,中文字段名,而且操作数据库的方式还是SQL语句拼接+ADO.NET,当然操作数据库的方式一点问题都没,但是最让我不能接受的就是SQL语句的拼接,因为数据库中大量中文表名,中文字段名的原因,导致一打开相关代码,黑压压一片汉字,着实辣眼睛,为了解决这个问题,编写了TQueryHelper帮助类。TQueryHelper的主要作用是避免在拼接SQL语句中出现中文,所以我的解决思路是:中文表名,中文字段名,可以利用特性(Attribute
  • 标签:C# 查询语句 SQL 表达式

由于一些历史原因,导致公司现有项目的数据库中存在大量中文表名,中文字段名,而且操作数据库的方式还是 SQL 语句拼接 + ADO.NET,当然操作数据库的方式一点问题都没,但是最让我不能接受的就是 SQL 语句的拼接,因为数据库中大量中文表名,中文字段名的原因,导致一打开相关代码,黑压压一片汉字,着实辣眼睛,为了解决这个问题,编写了 TQueryHelper 帮助类。

TQueryHelper 的主要作用是避免在拼接 SQL 语句中出现中文,所以我的解决思路是:中文表名,中文字段名,可以利用特性(Attribute)来与实体类的属性一一映射,查询语句通过 Lambda 表达式分块生成,然后利用 StringBuilder 进行拼接,因为是在现有项目上改进,所以 LinqToSql 和 EF 都不适合,因为 LinqToSql 和 EF 都需要连接数据库创建相应的实体类,这不符合需求,加上网上没有找到期望的类库,所以打算自己造,需要说明的是,Lambda 表达式生成 SQL 参考的这篇文章《由浅入深表达式树(二)遍历表达式树 作者:腾飞(Jesse)》,在此特别感谢作者。

上面说明的是编写 TQueryHelper 动机和过程,发本文的目的是期望自己写的帮助类能够帮助其他人,避免别人重复造轮子,另外由于本文水平有限,也期望大家能给出好的建议,让本人加以改进,还有如果有现成类库,本人就可以直接使用成熟的类库,这样也避免本人继续走弯路。

下面介绍一下 TQueryHelper 生成 SQL 语句的方式,增删改查虽然都有包括,但下面只介绍查询方面的,首先我们定义两个实体类:

class="brush:csharp;gutter:true;">[DataBaseT("文章表")]
public class TopicModel
{
    public int IdentityID { get; set; }

    [DataBaseT("标题")]
    public string Title { get; set; }

    [DataBaseT("类别")]
    public string TypeCode { get; set; }
}
[DataBaseT("文章类别表")]
public class TopicTypeModel
{
    public int IdentityID { get; set; }

    [DataBaseT("编号")]
    public string TypeCode { get; set; }

    [DataBaseT("名称")]
    public string TypeName { get; set; }
}

单表简单查询代码如下:

string querySql = new TQueryHelper<TopicModel>().Query()
                  .ToSql();
//生成的 SQL 语句如下:
select [文章表].* from [文章表] with(nolock)

查询前 10 条数据,并且只查询 IdentityID 和 标题字段代码如下:

string querySql = new TQueryHelper<TopicModel>().Query(10)
                  .Select(p => new { ID = p.IdentityID, p.Title })
                  .ToSql();

//生成的 SQL 语句如下:
select top 10 [文章表].[IdentityID] as ID,[文章表].[标题] from [文章表] with(nolock)

复杂一点的单表查询,包括 Where 语句,Order By 语句,Group By 语句的代码如下:

string querySql = new TQueryHelper<TopicModel>().Query()
                  .Select(p => new { ID = p.IdentityID, p.Title })
                  .Count(p => p.IdentityID, "Count")
                  .Where(p => p.IdentityID == 1)
                  .OrderDesc(p => p.IdentityID)
                  .Group(p => new { p.IdentityID, p.Title })
                  .ToSql();

//生成的 SQL 语句如下:
select [文章表].[IdentityID] as ID,[文章表].[标题],COUNT([文章表].[IdentityID]) as [Count] from [文章表] with(nolock) where [文章表].[IdentityID] = 1 group by [文章表].[IdentityID],[文章表].[标题] order by [文章表].[IdentityID] desc

下面来看看多表查询,简单双表内联连接查询代码如下:

string querySql = new TQueryHelper<TopicModel>().Query()
                  .InnerJoin<TopicTypeModel>((p, y) => p.IdentityID == y.IdentityID)
                  .ToSql();

//生成的 SQL 语句如下:
select [文章表].* ,[文章类别表].* from [文章表] with(nolock) inner join [文章类别表] with(nolock) on [文章表].[IdentityID]=[文章类别表].[IdentityID]

复杂一点的双表内联查询代码如下:

string querySql = new TQueryHelper<TopicModel>()
                  .Query()
                  .Select(p => new { ID = p.IdentityID, p.Title })
                  .Select<TopicTypeModel>(p => new { TypeID = p.IdentityID, p.TypeCode, p.TypeName })
                  .InnerJoin<TopicTypeModel>((p, y) => p.TypeCode == y.TypeCode)
                  .Where(p => p.TypeCode == "life" && p.IdentityID <= 20)
                  .Order(p => p.IdentityID)
                  .ToSql();

//生成的 SQL 语句如下:
select [文章表].[IdentityID] as ID,[文章表].[标题],[文章类别表].[IdentityID] as TypeID,[文章类别表].[编号],[文章类别表].[名称] from [文章表] with(nolock) inner join [文章类别表] with(nolock) on [文章表].[类别]=[文章类别表].[编号] where [文章表].[类别] = 'life' and [文章表].[IdentityID] <= 20 order by [文章表].[IdentityID] asc

TQueryHelper 支持任意张表内联连接/左连接/右连接查询,TQueryHelper 也支持联合查询和子查询,简单联合查询的代码如下:

string querySql = new TQueryHelper<TopicModel>()
                  .Query()
                  .Union<TopicModel>(
                      new TQueryHelper<TopicModel>().Query()
                  )
                  .ToSql();

//生成的 SQL 语句如下:
select [文章表].* from [文章表] with(nolock) union (select [文章表].* from [文章表] with(nolock))

复杂的联合查询代码也都依然支持,通过代码也能看到,联合查询之间互相无影响,所以逻辑可以相对复杂,子查询的处理方式跟联合查询类似,From In 子查询代码如下:

string querySql = new TQueryHelper<TopicModel>()
                  .Query()
                  .Select()
                  .FromIn<TopicModel>(
                      new TQueryHelper<TopicModel>()
                      .Query()
                  )
                  .ToSql();

//生成的 SQL 语句如下:
select [文章表].* from (select [文章表].* from [文章表] with(nolock)) as [文章表]

目前只提供了 Where In 的支持,代码如下:

string querySql = new TQueryHelper<TopicModel>()
                  .Query()
                  .Select()
                  .Where(p => p.IdentityID == 1)
                  .WhereIn<TopicTypeModel>(
                      p => p.TypeCode,
                      new TQueryHelper<TopicTypeModel>()
                      .Distinct()
                      .Select(p => new { TypeCode = p.TypeCode })
                  )
                  .ToSql();

//生成的 SQL 语句如下:
select [文章表].* from [文章表] with(nolock) where [文章表].[IdentityID] = 1 and [文章表].[类别] in (select distinct [文章类别表].[编号] from [文章类别表] with(nolock) )

至此,TQueryHelper 的主要功能都介绍完毕,TQueryHelper 支持 SQL 拼接的大部分逻辑实现,当然也支持生成参数(@)的 SQL 语句,这儿不一一列出,需要说明的是,虽然支持 CacheKey(就是根据 CacheKey 把查询语句缓存出来),但是还是无法避免表达式的参数传递,因为测试发现,比如下面的代码:

private void X<T>(Expression<Func<T, object>> lambda) {}
for (int index = 0; index < 10000; index ++ )
{
    X<TopicModel>(p => new { p.IdentityID, p.Title });
}

上面的代码,X 函数里面什么也没做,但是测试之后发现竟然需要消耗大概 130 毫秒左右,这儿实在是没想出办法来优化,所以调用生成一次 SQL 之后应该根据 KEY 值及时缓存,这样下次调用可以直接从缓存中拿出已拼接好的 SQL 语句,而不再需要通过 TQueryHelper 生成 SQL 语句,最后,还是希望看过本文的朋友提出宝贵的改进意见,或者给出成熟的类库链接,本人感激不进。源码下载地址:https://pan.baidu.com/s/1jHG3mSm 密码:ytm5

发表评论
用户名: 匿名