搭建一套自己实用的.net架构(3)续 【ORM Dapper+DapperExtensions+Lambda】
前言
继之前发的帖子【ORM-Dapper+DapperExtensions】,对Dapper的扩展代码也进行了改进,同时加入Dapper 对Lambda表达式的支持。
由于之前缺乏对Lambda的知识,还是使用了拿来主义。研究了些案例,总归有些问题:
1、只能生成sql、不能将值进行参数化。
2、lambda解析的代码对sql语法的多样式支持不够
3、不开源,反编译后发现可扩展性不强。
最后选择了Dos.ORM(lambda支持的很好,开源的),在这里尊重原创,大家有兴趣去支持下哈。
【作者博客:http://www.cnblogs.com/huxj/ 官方网站:http://ITdos.com/Dos/ORM/Index.html 】
开始研究Dos.ORM , 最后还是要是使用 Dapper 的, 同时还要基于 DapperExtensions的设计思想。
目的是把Dos.ORm的lambda解析核心代码借鉴过来,然后用Dapper去执行。
想法不错,但是实现起来废了一番周折。
大概改动如下:
1、在DapperExtensions原有接口中扩展lambda方法
2、基于DapperExtensions的缓存机制 ,替换了Dos.ORM 对各个字段的和表结构的映射方式。
3、沿用DapperExtensions 中的定义方言接口进行生成sql的扩展
4、扩展了若干方法, 同时去除了Dos.ORM的一些特性.
这里必须要维护DapperExtensions 对实体类的0入侵的原则。
最后发现想让ORM支持Lambda 的语法更多,最后还是要去扩展实体类。(各有利弊得失……)
语法
这里还是直接贴代码了,为了照顾对dapper不熟悉的同学,下面将dapper、DapperExtensions、DapperExtensions+lambda 的语法分块贴出来。
1、实体类
/// <summary>
/// HY:实体对象
/// </summary>
[Serializable]
public class UsersEntity
{
/// <summary>
/// 用户ID
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 登录名称
/// </summary>
public string LoginName { get; set; }
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 状态 1:启用 0禁用
/// </summary>
public int? Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdateTime { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
/// <summary>
/// Users:实体对象映射关系
/// </summary>
[Serializable]
public class UsersEntityORMMapper : ClassMapper<UsersEntity>
{
public UsersEntityORMMapper()
{
base.Table("Users");
//Map(f => f.UserInfo).Ignore();//设置忽略
//Map(f => f.Name).Key(KeyType.Identity);//设置主键 (如果主键名称不包含字母“ID”,请设置)
AutoMap();
}
}
2、原生态的Dapper
//做为Demo以下语法的支持, 声明的一个变量
IDbConnection connDemo = this.DBSession.Connection;
IEnumerable<UsersEntity> listDemo = connDemo.Query<UsersEntity>("SELECT * FROM Users AS u ");
IEnumerable<UsersEntity> listDemo1 = connDemo.Query<UsersEntity>("SELECT * FROM Users AS u WHERE u.UserId=@UserId AND u.LoginName LIKE @LoginName", new { UserId = 11, LoginName = "%王老五%" });
IEnumerable<UsersEntity> listDemo2 = connDemo.Query<UsersEntity>("SELECT * FROM Users AS u WHERE u.UserId IN @UserIds ", new { UserIds = new int[] { 1, 2, 3 }.AsEnumerable() });
string sqlDemo = @"SELECT * FROM Users AS u
LEFT JOIN UserInfo AS ui
ON u.UserId = ui.UserId";
IEnumerable<UsersModel> listDemo3 = connDemo.Query<UsersModel, UserInfoEntity, UsersModel>(sqlDemo, (user, userinfo) => { user.UserInfo = userinfo; return user; }).ToList();
string sqlDemo1 = @"SELECT * FROM Users AS u WHERE u.UserId=@UserId
SELECT * FROM UserInfo AS ui WHERE ui.UserId=@UserId";
using (var multi = connDemo.QueryMultiple(sqlDemo1, new { UserId = 1 }))
{
var user = multi.Read<UsersEntity>().Single();
var userinfo = multi.Read<UserInfoEntity>().Single();
}
connDemo.Execute("sql 语句");
//存储过程
var UsersEntity = connDemo.Query<UsersEntity>("spGetUser", new { Id = 1 }, commandType: CommandType.StoredProcedure).SingleOrDefault();
2、DapperExtensions
//实体类
UsersEntity entity = new UsersEntity();
int userId = this.Insert(entity);//插入
bool isSuccess = this.Update(entity);//更新
int count = this.Delete(entity);//删除
entity = this.GetById(1);//获得实体
int count1 = this.Count(new { ID = 1 }); //数量
//查询所有
IEnumerable<UsersEntity> list = this.GetAll();
//条件查询
IList<ISort> sort = new List<ISort>();
sort.Add(new Sort { PropertyName = "UserId", Ascending = false });
IEnumerable<UsersEntity> list1 = this.GetList(new { UserId = 1, Name = "123" }, sort);
//orm 拼接条件 查询 繁琐 不灵活 不太好用
IList<IPredicate> predList = new List<IPredicate>();
predList.Add(Predicates.Field<UsersEntity>(p => p.LoginName, Operator.Like, "不知道%"));
predList.Add(Predicates.Field<UsersEntity>(p => p.UserId, Operator.Eq, 1));
IPredicateGroup predGroup = Predicates.Group(GroupOperator.And, predList.ToArray());
list = this.GetList(predGroup);
//分页查询
long allRowsCount = 0;
this.GetPageList(1, 10, out allRowsCount, new { ID = 1 }, sort);
3、DapperExtensions+lambda
//SELECT [Users].[UserId],
// [Users].[LoginName],
// [Users].[Password]
//FROM [Users]
//WHERE [Users].[LoginName] = @LoginName_1
var fromDemo = this.LambdaQuery().Select(p => new { p.UserId, p.LoginName, p.Password }) //不支持As
.Where(p => p.LoginName == "很好很强大");
//支持 返回 DataReader、DataSet、DataTable、 泛型集合
fromDemo.ToDataReader();
fromDemo.ToDataSet();
fromDemo.ToDataTable();
IEnumerable<UsersModel> list = fromDemo.ToList<UsersModel>();
var select = new Select<UsersEntity>();
select.AddSelect(p => p.Remark.As("Remark")); //Expression<Func<T, bool>>类型支持 as 语法
fromDemo = this.LambdaQuery().AddSelect(select);
// SELECT [Users].[UserId],
// [Users].[LoginName],
// [Users].[Password],
// [Users].[Status],
// [Users].[CreateTime],
// [Users].[UpdateTime],
// [Users].[Remark]
//FROM [Users]
//WHERE (
// (
// ([Users].[LoginName] LIKE @LoginName_1)
// AND ([Users].[Status] NOT IN (@Status_2, @Status_3, @Status_4))
// )
// AND ([Users].[CreateTime] >= @CreateTime_5)
// )
// AND ([Users].[UpdateTime] IS NOT NULL)
var fromDemo2 = this.LambdaQuery().Where(p => p.LoginName.Like("%王老五%") //like
&& p.Status.NotIn<string>("1", "2", "3") //in or not in
&& p.CreateTime >= Convert.ToDateTime("2016-01-21") //时间比较
&& p.UpdateTime.IsNotNull() //is null
);
//SELECT [Users].[UserId],
// [Users].[LoginName],
// [Users].[Password],
// [Users].[Status],
// [Users].[CreateTime],
// [Users].[UpdateTime],
// [Users].[Remark]
//FROM [Users]
//WHERE (
// (
// ([Users].[LoginName] LIKE @LoginName_1)
// AND ([Users].[Status] = @Status_2)
// )
// OR ([Users].[UserId] = @UserId_3)
// )
var where = new Where<UsersEntity>();
where.And(p => p.LoginName.Like("%李二蛋%") && p.Status == 1);
where.Or(p => p.UserId == 1);
var fromDemo3 = this.LambdaQuery().Where(where);
//SELECT [Users].[UserId],
// [Users].[LoginName],
// [Users].[Password],
// [Users].[Status],
// [Users].[CreateTime],
// [Users].[UpdateTime],
// [Users].[Remark]
//FROM [Users]
//ORDER BY
// CreateTime ASC,
// UpdateTime ASC,
// UserId DESC
var fromDemo4 = this.LambdaQuery().OrderBy(p => new { p.CreateTime, p.UpdateTime }).AddOrderByDescending(p => new { p.UserId });
//"SELECT * FROM [Users] INNER JOIN UserInfo ON ([Users].[UserId] = [UserInfo].[UserId]) "
var fromDemo5 = this.LambdaQuery().InnerJoin<UserInfoEntity>((u, ui) => u.UserId == ui.UserId);
//SELECT DISTINCT TOP 100 *
//FROM [Users] WITH (NOLOCK) INNER
// JOIN UserInfo WITH (NOLOCK)
// ON ([Users].[UserId] = [UserInfo].[UserId])
var fromDemo6 = this.LambdaQuery()
.InnerJoin<UserInfoEntity>((u, ui) => u.UserId == ui.UserId).WithNoLock().Top(100).Distinct();
//SELECT TOP(10) [_proj].*
//FROM (
// SELECT ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) AS [_row_number],
// *
// FROM [Users] WITH (NOLOCK) LEFT
// JOIN UserInfo WITH (NOLOCK)
// ON ([Users].[UserId] = [UserInfo].[UserId])
// WHERE ([Users].[UserId] > @UserId_1)
// AND ([UserInfo].[Sex] = @Sex_2)
// ) [_proj]
//WHERE [_proj].[_row_number] >= @_pageStartRow
//ORDER BY
// [_proj].[_row_number]
var fromDemo7 = this.LambdaQuery()
.LeftJoin<UserInfoEntity>((u, ui) => u.UserId == ui.UserId).WithNoLock()
.Where<UserInfoEntity>((u, ui) => u.UserId > 1 && ui.Sex == 1)
.Page(2, 10);
//DELETE
//FROM [Users]
//WHERE ([Users].[Status] = @Status_1)
// AND (
//[Users].[CreateTime] > @CreateTime_2
var deleteDemo = this.LambdaDelete()
.Where(p => p.Status == 1 && p.CreateTime > DateTime.Now);
//UPDATE [Users]
//SET [Users].[Remark] = @Remark_3
//WHERE [Users].[Status] = @Status_4
var updateDemo = this.LambdaUpdate()
.Set(p => p.Remark == "Remark")
.Where(p => p.Status == 1);
对于lambda 支持 select + As 、where 、各种左右连接、 orderby 、grouy by、 HAVING、 WITH(NOLOCK) (支持sqlserver)、 Top、Distinct、
(支持sql垮数据库查询,加入DbName、SchemaName配置)
简单的语法都支持了,但是还有些特殊的sql 语法 介于Lambda的语法问题暂时没办法支持。不过Dos.ORM做到了一些特殊的支持。
之前也和Dos.ORM的作者交流过。 目前都不支持 select * from User a INNER join User b on a.id=b.pid 这类 别名且自join查询,实现起来很麻烦。
这里我就放弃了,有些功能在考虑到性能和设计方面得不偿失。
比如一个特别复杂的sql ,非要用ORM来实现,那其实已经超出ORM的能力范围了。且不论性能问题和代码支持问题, 单单代码可读性就降低很多啊
相信直接看sql 比直接看 orm语法 看的爽吧 。
性能:
用lambda生成sql用时也就2,3 毫秒的样子, 所以在执行和映射能力方面我就不担心了。最后还是写了个小测试:
之前有很多小伙伴不太了解如何使用或者调用, 这里简单的写个Demo, (下载地址在下面 )
1.针对Repository的类图如下:
2、Demo的 架构如下:
欢迎老大们拍砖指点。
觉得有用请点下推荐吧,你的推荐是我发帖的动力。
https://git.oschina.net/hy59005271/DapperExtensions_Demo
有新的扩展和bug会及时更新
相关文章:
搭建一套自己实用的.net架构(3)【ORM-Dapper+DapperExtensions】
原文链接:http://www.cnblogs.com/hy59005271/p/5604118.html