基于 Dapper
、Dapper-Extensions
构建的微型 ORM 类库,提供一个包含增、删、改、查等常用方法的数据访问层基类,支持用 Lambda
表达式书写查询和更新条件。
- 零配置,开箱即用。
- 数据库表、实体类型自动映射,主键自动映射。实体类上无需定义 Attribute。
- 灵活易用的增、删、改、查、分页查询等常用重载方法,单表操作无需编写任何 SQL 语句。
- 查询和更新条件支持
Lambda
表达式组合,自动生成安全参数化的 SQL 语句。 - 提供 SQL 语句、存储过程执行方法,返回结果集自动模型映射,比 DataSet 效率高。
- 支持部分字段更新,无变化字段不更新。
- 数据库表字段变化时重新生成实体类即可,数据访问层无需重新生成。
- 基类定义了 IDbConnection 属性,所有
Dapper
、Dapper-Extensions
方法都能使用。 - 完善的单元测试。
- 命名约定:实体类名和数据库表名应匹配,实体属性名与表字段名应匹配。主键字段名应以
Id
命名或结尾 - 限制:多表联合查询还是需要编写 SQL 语句或者存储过程。
https://www.nuget.org/packages/DapperDal
PM> Install-Package DapperDal
https://arbing.github.io/DapperDal
定义实体类 PersonEntity
/// <summary>
/// 人员信息表实体类
/// </summary>
public class PersonEntity
{
public long PersonId { get; set; }
public string PersonName { get; set; }
public int CarId { get; set; }
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public short IsActive { get; set; }
}
数据访问层定义DAL类 PersonDal,继承自 DalBase<PersonEntity, long>
/// <summary>
/// 人员信息表数据访问类
/// </summary>
public class PersonDal : DalBase<PersonEntity, long>
{
public PersonDal() : base(ConnectionNames.Default)
{
}
...
}
单条插入
var personDal = new PersonDal();
PersonEntity p = new PersonEntity { PersonName = "Foo", CreateTime = DateTime.Now, UpdateTime = DateTime.Now };
long id = personDal.Insert(p);
多条批量插入
var personDal = new PersonDal();
PersonEntity p1 = new PersonEntity { PersonName = "Foo", CreateTime = DateTime.Now, UpdateTime = DateTime.Now };
PersonEntity p2 = new PersonEntity { PersonName = "Bar", CreateTime = DateTime.Now, UpdateTime = DateTime.Now };
PersonEntity p3 = new PersonEntity { PersonName = "Baz", CreateTime = DateTime.Now, UpdateTime = DateTime.Now };
personDal.Insert(new[] { p1, p2, p3 });
主键获取
var personDal = new PersonDal();
long personId = 1;
PersonEntity person = personDal.Get(id);
条件获取
var personDal = new PersonDal();
PersonEntity person = personDal.GetFirst(p => p.PersonId = 1);
PersonEntity person = personDal.GetFirst(p => p.IsActive != 1);
PersonEntity person = personDal.GetFirst(p => UpdateTime >= DateTime.Today);
PersonEntity person = personDal.GetFirst(p => p.PersonId = 1 && p.IsActive == 1);
PersonEntity person = personDal.GetFirst(p => p.PersonId = 1 || p.PersonName = "Foo");
PersonEntity person = personDal.GetFirst(p => p.IsActive == 1 && (p.PersonName == "Foo" || p.CarId == 3));
PersonEntity person = personDal.GetFirst(p => p.PersonName.Equals("Foo"));
PersonEntity person = personDal.GetFirst(p => p.PersonName.Contains("a"));
PersonEntity person = personDal.GetFirst(p => p.PersonName.StartsWith("Ba"));
PersonEntity person = personDal.GetFirst(p => p.PersonName.EndsWith("az"));
var carIds = new[] { p2.CarId, 3, 2};
PersonEntity person = personDal.GetFirst(p => carIds.Contains(p.CarId));
判断实体是否存在
var personDal = new PersonDal();
bool isExsit = personDal.Exsit(id: 1);
bool isExsit = personDal.Exsit(p => p.PersonId = 1);
更新实体
var p2 = personDal.Get(id);
p2.IsActive = 1;
p2.PersonName = "Baz";
var result = personDal.Update(p2);
更新指定实体指定属性
var p2 = personDal.Get(id);
p2.PersonName = "Baz";
p2.CarId = 2;
p2.IsActive = 1;
bool result = personDal.Update(p2, new[] { "personName", "CarId", "CarName" });
bool result = personDal.Update(p2, new { personName = "Baz", CarId = 2 });
bool result = personDal.Update(p2.PersonId, new { personName = "Baz", CarId = 2 });
var personName = p2.PersonName;
bool result = personDal.Update(new { p2.PersonId, personName, p2.CarId, CarName = "CarName" });
根据指定更新条件更新实体指定属性
var personName = p2.PersonName;
bool result = personDal.Update(new { personName, p2.CarId, CarName = "CarName" }, p => p.PersonId == p2.PersonId);
删除实体
PersonEntity p2 = personDal.Get(id);
bool result = personDal.Delete(p2);
bool result = personDal.Delete(p2.PersonId);
bool result = personDal.Delete(p => p.PersonName == "Bar");
列表查询
IEnumerable<PersonEntity> persons = personDal.GetList().ToList();
IEnumerable<PersonEntity> persons = personDal.GetList(SortDirection.Descending, p => p.CarId);
IEnumerable<PersonEntity> persons = personDal.GetList(p.IsActive == 1 && p.PersonName == "c");
var predicate = PredicateBuilder.True<PersonEntity>();
predicate = predicate.And(p => p.IsActive == 1);
predicate = predicate.And(p => p.PersonName == "c");
IEnumerable<PersonEntity> persons = personDal.GetList(predicate);
var sort = new List<Sort>() { new Sort { PropertyName = "CarId", Ascending = false } };
IEnumerable<PersonEntity> persons = personDal.GetList(p => p.IsActive == 1, sort).ToList();
IEnumerable<PersonEntity> persons = personDal.GetList(p => p.IsActive == 1, SortDirection.Descending, p => p.CarId).ToList();
生成的 SQL
SELECT [Person].[PersonId], [Person].[PersonName], [Person].[CarId], [Person].[CreateTime], [Person].[UpdateTime], [Person].[IsActive]
FROM [Person] WITH (NOLOCK)
WHERE ([Person].[IsActive] = @IsActive_0)
ORDER BY [Person].[CarId] DESC
获取总条数
int count = personDal.Count(p => p.IsActive == 1)
生成的 SQL
SELECT COUNT(*) AS [Total] FROM [Person] WITH (NOLOCK)
WHERE ([Person].[IsActive] = @IsActive_0)
列表分页查询
IEnumerable<PersonEntity> persons = personDal.GetListPaged(p => p.IsActive == 1, new { CarId = SortDirection.Descending }, pageNumber: 1, itemsPerPage: 20).ToList()
生成的 SQL
SELECT TOP(20) [_proj].[PersonId], [_proj].[PersonName], [_proj].[CarId], [_proj].[CreateTime], [_proj].[UpdateTime], [_proj].[IsActive]
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY [Person].[CarId] DESC) AS [_row_number],
[Person].[PersonId], [Person].[PersonName], [Person].[CarId], [Person].[CreateTime], [Person].[UpdateTime], [Person].[IsActive]
FROM [Person] WITH (NOLOCK)
WHERE ([Person].[IsActive] = @IsActive_0)) [_proj]
WHERE [_proj].[_row_number] >= @_pageStartRow
ORDER BY [_proj].[_row_number]
执行查询语句
IEnumerable<PersonModel> list = personDal.Query<PersonModel>(
"select PersonName as Name, CarId from Person where CarId = @CarId", new { CarId = 3 });
执行查询存储过程
IEnumerable<PersonModel> list = personDal.Query<PersonModel>(
"dbo.P_GetPersonModelsByCarId",
new { CarId = 3 }, System.Data.CommandType.StoredProcedure);
执行多结果集查询语句
Tuple<IEnumerable<PersonEntity>, IEnumerable<PersonModel>> tuple = personDal.QueryMultiple<PersonEntity, PersonModel>(
"select * from Person where CarId = @CarId;select PersonName AS [Name], CarId from Person where CarId = @CarId",
new { CarId = 3 });
执行多结果集查询存储过程
Tuple<IEnumerable<PersonEntity>, IEnumerable<PersonModel>> tuple = personDal.QueryMultiple<PersonEntity, PersonModel>(
"P_GetPersonMultipleModelsByCarId", new { CarId = 3 }, System.Data.CommandType.StoredProcedure);
执行语句
int affected = personDal.Execute("update Person set IsActive = 1 where CarId = @CarId", new { CarId = 3 });
执行存储过程
int affected = personDal.Execute("P_SetPersonsByCarId", new { CarId = 3 }, System.Data.CommandType.StoredProcedure);
执行带返回参数的存储过程
var parameters = new DynamicParameters(new { CarId = 3 });
parameters.Add("TotalCount", dbType: System.Data.DbType.Int32, direction: System.Data.ParameterDirection.Output);
int affected = personDal.Execute("P_SetPersonsByCarId_OutputCount", parameters, System.Data.CommandType.StoredProcedure);
int totalCount = parameters.Get<int>("TotalCount");
执行带返回参数的查询存储过程
var parameters = new DynamicParameters(new { CarId = 3 });
parameters.Add("TotalCount", dbType: System.Data.DbType.Int32, direction: System.Data.ParameterDirection.Output);
IEnumerable<PersonModel> list = personDal.Query<PersonModel>(
"dbo.P_GetPersonModelsByCarId_OutputCount",
parameters, System.Data.CommandType.StoredProcedure);
int totalCount = parameters.Get<int>("TotalCount");
其他常用方法
打开新的 IDbConnection
OpenConnection
执行SQL语句,返回第一行第一列数据
ExecuteScalar
获取前N条
GetTop
逻辑删除
SoftDelete
逻辑删除或激活
SwitchActive
常见应用
/// <summary>
/// 请求分页数据时的参数基类
/// </summary>
public class PagedParam
{
/// <summary>
/// 初始化
/// </summary>
public PagedParam()
{
PageIndex = 1;
PageSize = 10;
}
/// <summary>
/// 当前页索引
/// </summary>
public int PageIndex { get; set; }
/// <summary>
/// 每页显示的记录数
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// 要分页的数据总数
/// </summary>
public int RecordCount { get; set; }
}
/// <summary>
/// 获取人员分页列表的查询参数
/// </summary>
public class GetPersonPagedListParam : PagedParam
{
public string PersonName { get; set; }
public int CarId { get; set; }
/// <summary>
/// 创建起始时间
/// </summary>
public DateTime? BeginCreateTime { get; set; }
/// <summary>
/// 创建结束时间
/// </summary>
public DateTime? EndCreateTime { get; set; }
}
/// <summary>
/// 获取人员分页列表的返回实体
/// </summary>
public class GetPersonPagedListOutputDto // : PersonEntity
{
/// 人员信息
/// 其他信息
}
/// <summary>
/// 人员信息表数据访问类
/// </summary>
public class PersonDal : DalBase<PersonEntity, long>
{
public PersonDal() : base(ConnectionNames.Default)
{
}
/// <summary>
/// 获取人员分页列表
/// </summary>
/// <param name="param">查询参数</param>
/// <returns>人员分页列表</returns>
public PagingList<GetPersonPagedListOutputDto> GetPersonPagedList(GetPersonPagedListParam param)
{
var parameters = new DynamicParameters(param).Output(param, p => p.RecordCount);
var list = Query<GetPersonPagedListOutputDto>(
"p_GetPersonPagedList",
parameters,
commandType: CommandType.StoredProcedure)
.ToList();
return PagingList.Create(list, param.RecordCount);
}
}
- 逻辑删除方法
SoftDelete
、SwitchActive
默认更新字段UpdateTime = DateTime.Now
- 添加返回 DataSet 的查询方法:
QueryDataSet
- 重构,合并
Dapper-Extensions
到DapperDal
,然后移除Dapper-Extensions
- 删除方法
QueryFirstOrDefault
,可以使用QueryFirst
替换 - 添加重载方法
OpenConnection
、Execute
、Query
, 支持传入其他 DB 连接串
- 添加逻辑删除或激活方法
SwitchActive
- 删除方法
GetFirstOrDefault
,可以使用GetFirst
替换 - 添加支持主键 ID 的重载方法
Update
、Delete
- 配置项
SoftDeleteProps
迁移到DapperDal
中,新添加配置项SoftActiveProps
- 添加谓词表达式组合扩展方法(来自alexfoxgill/ExpressionTools)
- 优化
Exsit
、Count
方法
- 优化更新方法,支持传递小写字段名
- 添加判断实体是否存在方法:
Exsit
- 添加逻辑删除方法:
SoftDeleteById
- 添加实体查询方法:
GetFirstOrDefault
、QueryFirstOrDefault
、QueryFirst
- 添加SQL执行方法:
Execute
、ExecuteScalar
- 添加实体查询方法:
GetFirst
、GetTop
- 优化实体查询方法,添加实体集合返回前是否要缓冲的设置点
- 优化逻辑删除,添加更新属性及值的设置点
- 生成查询 SQL 时,添加
WITH (NOLOCK)
- 添加设置项:SQL 输出方法
- 添加逻辑删除方法
SoftDelete
- 表达式转换用
QueryBuilder
替换ExpressionVisitor
实现,以支持多个查询条件(来自ryanwatson/Dapper.Extensions.Linq)
- 添加支持多个实体查询的
Query
方法
- 添加更新部分属性的
Update
方法(来自vilix13/Dapper-Extensions) - 添加使用谓词、匿名对象或
lambda
表达式作条件的Update
方法
- 整合
Abp.Dapper
,为Dapper-Extensions
添加lambda
表达式功能(来自Abp.Dapper)
Apache License 2.0