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