.NetCore中使用Dapper

Dapper是什么?

Dapper是开源的、轻量级,高性能的ORM(对象关系映射)。

Dapper的特点:

一、轻量:Dapper的GitHub地址:https://github.com/StackExchange/Dapper/tree/main/Dapper,它的核心代码是SqlMapper.cs。代码量不多,编辑后所占空间也比较小。

二、高性能:它通过Emit反射IDataReader的序列队列,快速的映射出对象。

三、Dapper更倾向于面向SQL,支持多种数据库。

 .NetCore中简单封装使用Dapper

1、引入Dapper和Dapper.Contrib

2、创建仓储接口

 1 public interface IRepository<T> where T:BaseEntity
 2     {
 3         T GetById(string id);
 4         IEnumerable<T> GetAll();
 5         IEnumerable<T> GetBySql(string sql, Dictionary<string, object> parameter, CommandType commandType);
 6         IEnumerable<T> GetByPaging(string sql, Dictionary<string, object> parameters, CommandType commandType);
 7        
 8         void Add(T entity);
 9         void Delete(T entity);
10         void Update(T Entity);
11 
12     }

 

3、创建仓储基类

 1    public class BaseRepository<T> : IRepository<T> where T : BaseEntity
 2     {
 3         private IDbConnection _connection;
 4         public BaseRepository(IConfiguration configuration)
 5         {
 6             this._connection = new MySqlConnection(configuration.GetConnectionString("ListingDb"));
 7         }
 8 
 9         public IEnumerable<T> GetAll()
10         {
11             var result = _connection.GetAll<T>();
12             return result;
13         }
14 
15         public T GetById(string id)
16         {
17             var result = _connection.Get<T>(id);
18             return result;
19         }
20 
21         public IEnumerable<T> GetByPaging(string sql, Dictionary<string, object> parameters, CommandType commandType)
22         {
23             //TODO query paging
24             return null;
25         }
26 
27         public IEnumerable<T> GetBySql(string sql, Dictionary<string, object> parameters, CommandType commandType)
28         {
29             var result = _connection.Query<T>(sql, parameters, commandType: commandType);
30             return result;
31         }
32 
33         public void Add(T entity)
34         {
35             _connection.Insert(entity, null);
36         }
37         public void Update(T entity)
38         {
39             _connection.Update(entity);
40         }
41         public void Delete(T entity)
42         {
43             _connection.Delete(entity);
44         }
45     }

4、在startup.cs中注入仓储类

 

services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));

5、定义具体业务类进行调用(略)

 

进阶--实现Dapper+UnitOfWork

想了解UOW(UnitOfWork)可参照:https://martinfowler.com/eaaCatalog/unitOfWork.html

在【简单封装dapper】中,不难发现它主要是针对单个对象的操作。即使通过注入多个对象的仓储进行统一处理统一事务的多表,但是还是缺少了事务的支持。就像之前写的关于数据库访问的封装(https://www.cnblogs.com/johnyong/p/14152891.html)一样,需要将事务进行抽离,即做成单独的工作单元,实现对对象状态的跟踪,实现事务。

以下是简单的实现

1、定义IUnitOfWork接口

1     public interface IUnitOfWork
2     {
3         Guid Id { get; }
4         IDbConnection Connection { get; }
5         IDbTransaction Transaction { get; }
6         void Begin();
7         void Commit();
8         void Rollback(); 
9     }

2、定义UnitOfWork

 1     public sealed class UnitOfWork : IUnitOfWork, IDisposable
 2     {
 3         private Guid _id = Guid.Empty;
 4         private IDbConnection _connection = null;
 5         private IDbTransaction _transaction = null;
 6         private bool _disposed = false;
 7  
 8         public UnitOfWork(IConfiguration configuration)
 9         {
10             _id = new Guid();
11             _connection = new MySqlConnection(configuration.GetConnectionString("SimpleTestConnection"));
12 
13 
14         }
15 
16 
17         public Guid Id
18         {
19             get { return _id; }
20         }
21 
22         public IDbConnection Connection
23         {
24             get { return _connection; }
25         }
26         public IDbTransaction Transaction
27         {
28             get { return _transaction; }
29         }
30 
31         public void Begin()
32         {
33             if (_connection.State != ConnectionState.Open)
34             {
35                 _connection.Open();
36             }
37             _transaction = _connection.BeginTransaction();
38         }
39 
40         public void Commit()
41         {
42             _transaction.Commit();
43             Dispose();
44         }
45 
46         public void Rollback()
47         {
48             _transaction.Rollback();
49             Dispose();
50         }
51 
52 
53         public void Dispose()
54         {
55             Dispose(true);
56             GC.SuppressFinalize(this);
57         }
58 
59         public void Dispose(bool disposing)
60         {
61             if (_disposed)
62                 return;
63 
64             if (disposing)
65             {
66                 _transaction?.Dispose();
67                 _connection?.Dispose();
68             }
69 
70             _transaction = null;
71             _connection = null;
72             _disposed = true;
73         }
74         ~UnitOfWork()
75         {
76             Dispose(false);
77         }
78     }

3、修改BaseRepository

 1     public class BaseRepository<T> : IRepository<T> where T : BaseEntity
 2     {
 3         private IUnitOfWork _unitOfWork;
 4         public BaseRepository(IUnitOfWork unitOfWork)
 5         {
 6             this._unitOfWork = unitOfWork;
 7         }
 8        
 9         public IEnumerable<T> GetAll()
10         {
11             var result = _unitOfWork.Connection.GetAll<T>();
12             return result;
13         }
14 
15         public T GetById(string id)
16         {
17             var result = _unitOfWork.Connection.Get<T>(id);
18             return result;
19         }
20 
21         public IEnumerable<T> GetByPaging(string sql, Dictionary<string, object> parameters, CommandType commandType)
22         {
23             //TODO query paging
24             return null; 
25         }
26 
27         public IEnumerable<T> GetBySql(string sql, Dictionary<string, object> parameters, CommandType commandType)
28         {
29             var result = _unitOfWork.Connection.Query<T>(sql, parameters, commandType: commandType);
30             return result;
31         }
32 
33         public void Add(T entity)
34         {
35             _unitOfWork.Connection.Insert(entity,null);
36         }
37         public void Update(T entity)
38         {
39             _unitOfWork.Connection.Update(entity);
40         }
41         public void Delete(T entity)
42         {
43             _unitOfWork.Connection.Delete(entity);
44         }
45     }

 

4、定义事务特性,用于实现aop(需要引入AspectCore.DynamicProxy)

 1     public class SystemTransactionAttribute : AbstractInterceptorAttribute
 2     {
 3         IUnitOfWork _unitOfWork { get; set; }
 4 
 5         public async override Task Invoke(AspectContext context, AspectDelegate next)
 6         {
 7             try
 8             {
 9                 _unitOfWork = context.ServiceProvider.GetService(typeof(IUnitOfWork)) as IUnitOfWork;
10                 _unitOfWork.Begin();
11                 await next(context);
12                 _unitOfWork.Commit();
13             }
14             catch (Exception ex )
15             {
16                 _unitOfWork.Rollback();
17                 throw new Exception("SystemTransaction error",ex);
18             }
19         }
20     }

 

5、注入服务

在startup.cs注入UnitOfWork

            services.AddScoped<IUnitOfWork, UnitOfWork>();
            services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));

 

修改Program.cs

 1     public class Program
 2     {
 3         public static void Main(string[] args)
 4         {
 5             CreateHostBuilder(args).Build().Run();
 6         }
 7 
 8         public static IHostBuilder CreateHostBuilder(string[] args) =>
 9             Host.CreateDefaultBuilder(args)
10                 .ConfigureWebHostDefaults(webBuilder =>
11                 {
12                     webBuilder.UseStartup<Startup>();
13                 }).UseDynamicProxy();
14     }

 

6、测试示例代码

 1     public class ListingService: IListingService
 2     {
 3         private IRepository<Listing> _listingRepository;
 4         private IRepository<ListingDetail> _listingDetailRepository;
 5 
 6         public ListingService(IRepository<Listing> listingRepository,IRepository<ListingDetail> listingDetailRepository)
 7         {
 8             this._listingRepository = listingRepository;
 9             this._listingDetailRepository = listingDetailRepository;
10         }
11         [SystemTransaction]
12         public void AddListing(ListingContract contract)
13         { 
14             var listing = new Listing()
15             {
16                 Id = ObjectId.GenerateNewId().ToString(), 
17                 Price = contract.Price,
18                 Quantity = contract.Quantity,
19                 Title=contract.Title,
20                 Remark="john_yong test"
21             };
22             _listingRepository.Add(listing);
23             foreach (var item in contract.DetailList)
24             {
25                 var listingDetail = new ListingDetail()
26                 {
27                     Id ="",//设置Id为空抛出异常 //ObjectId.GenerateNewId().ToString(),
28                     ListingId = listing.Id,
29                     Quantity = item.Quantity,
30                     SKU = item.SKU,
31                 };
32                 _listingDetailRepository.Add(listingDetail);
33             } 
34             
35         }
36     }

 

注:

使用dapper.Contrib,默认数据库表明为实体名称的复数形式,我们可以使用[Table]特性进行声明表名称。

Dapper.Contrib.Extensions扩展而言:自增主键用[Key]标志(默认为自增主键),非自增主键必须用[ExplicitKey]标志,否则即使我们给Id指定值再进行插入数据表,最终Id还是为空。

 

 

--------------------

本文地址: https://www.cnblogs.com/johnyong/p/14433155.html

 

.NetCore中使用Dapper

上一篇:隐藏android中EditText的下划线-by:nixs


下一篇:Android实现倒计时效果(天-时-分-秒)