准备抽象NHibernate和EntityFramework
准备抽象NHibernate和EntityFramework
背景
考虑到目前中小企业应用的主流是ORM,我准备在NHibernate和EntityFramework之间找到一个抽象层,也就是说我准备只支持NHibernate和EntityFramework。
思路
NH和EF都实现了“工作单元”和“主键映射”这两种企业应用模式,而这两种模式其实就是管理一种状态机,如下图:
实现
工作单元接口
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Happy.Domain 8 { 9 /// <summary> 10 /// 工作单元接口。 11 /// </summary> 12 /// <remarks> 13 /// 聚合状态: 14 /// <list type="number"> 15 /// <item> transient:实例存在于内存中,但不存在于工作单元和数据库中。 </item> 16 /// <item> persistent in database:实例存在于数据库中。 </item> 17 /// <item> persistent in unitofwork:实例存在于工作单元中。 </item> 18 /// <item> detached:实例存在于内存和数据库中,但不存在于工作单元中。 </item> 19 /// </list> 20 /// 合法转换: 21 /// <list type="number"> 22 /// <item> transient > Save -> persistent in unitofwork,Flush时会生成Insert Sql,场景:从UI层创建实例,执行创建。 </item> 23 /// <item> detached -> Update -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,执行修改(支持离线乐观并发)。 </item> 24 /// <item> detached -> Persist -> persistent in unitofwork,Flush时不会生成Sql,场景:将实例从另一个工作单元脱钩,添加到当前工作单元。 </item> 25 /// <item> detached -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从UI层重建实例,删除记录。 </item> 26 /// <item> detached -> Merge -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,合并到从数据库重建的实例,执行修改(不支持离线乐观并发)。 </item> 27 /// <item> persistent in unitofwork -> Evict -> detached,Flush时不会生成Sql,场景:将实例从当前工作单元脱钩,添加到另一个工作单元。 </item> 28 /// <item> persistent in unitofwork -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从数据库重建实例,删除记录。 </item> 29 /// <item> persistent in unitofwork -> Flush -> persistent in database,提交工作单元,会生成SQL,场景:执行完一系列Create、Update和Delete后统一提交,只产生一次数据库往返。 </item> 30 /// <item> persistent in database -> Load -> persistent in unitofwork,从数据库重建实例。 </item> 31 /// <item> persistent in database -> Refresh -> persistent in unitofwork,从数据库刷新实例,场景:使用存储过程修改了一个实例,使用此方法重新刷新一下。 </item> 32 /// </list> 33 /// </remarks> 34 public interface IUnitOfWork : IDisposable 35 { 36 /// <summary> 37 /// 判断 <paramref name="item"/> 是否 persistent in unitofwork。 38 /// </summary> 39 bool Contains<TAggregateRoot> (TAggregateRoot item) 40 where TAggregateRoot : AggregateRoot; 41 42 /// <summary> 43 /// transient > Save -> persistent in unitofwork,Flush时会生成Insert Sql,场景:从UI层创建实例,执行创建。 44 /// </summary> 45 void Save<TAggregateRoot> (TAggregateRoot item) 46 where TAggregateRoot : AggregateRoot; 47 48 /// <summary> 49 /// detached -> Update -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,执行修改(支持离线乐观并发)。 50 /// </summary> 51 void Update<TAggregateRoot> (TAggregateRoot item) 52 where TAggregateRoot : AggregateRoot; 53 54 /// <summary> 55 /// detached -> Persist -> persistent in unitofwork,Flush时不会生成Sql,场景:将实例从另一个工作单元脱钩,添加到当前工作单元。 56 /// </summary> 57 void Persist<TAggregateRoot> (TAggregateRoot item) 58 where TAggregateRoot : AggregateRoot; 59 60 /// <summary> 61 /// 执行如下两种转换: 62 /// <list type="number"> 63 /// <item> detached -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从UI层重建实例,删除记录。 </item> 64 /// <item> persistent in unitofwork -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从数据库重建实例,删除记录。 </item> 65 /// </list> 66 /// </summary> 67 void Delete<TAggregateRoot> (TAggregateRoot item) 68 where TAggregateRoot : AggregateRoot; 69 70 /// <summary> 71 /// detached -> Merge -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,合并到从数据库重建的实例,执行修改(不支持离线乐观并发)。 72 /// </summary> 73 void Merge<TAggregateRoot> (TAggregateRoot item) 74 where TAggregateRoot : AggregateRoot; 75 76 /// <summary> 77 /// persistent in unitofwork -> Evict -> detached,Flush时不会生成Sql,场景:将实例从当前工作单元脱钩,添加到另一个工作单元。 78 /// </summary> 79 void Evict<TAggregateRoot> (TAggregateRoot item) 80 where TAggregateRoot : AggregateRoot; 81 82 /// <summary> 83 /// persistent in unitofwork -> Flush -> persistent in database,提交工作单元,会生成SQL,场景:执行完一系列Create、Update和Delete后统一提交,只产生一次数据库往返。 84 /// </summary> 85 void Flush(); 86 87 /// <summary> 88 /// persistent in database -> Load -> persistent in unitofwork,从数据库重建实例。 89 /// </summary> 90 TAggregateRoot Load<TAggregateRoot> (Guid id) 91 where TAggregateRoot : AggregateRoot; 92 93 /// <summary> 94 /// persistent in database -> Refresh -> persistent in unitofwork,从数据库刷新实例,场景:使用存储过程修改了一个实例,使用此方法重新刷新一下。 95 /// </summary> 96 void Refresh<TAggregateRoot> (TAggregateRoot item) 97 where TAggregateRoot : AggregateRoot; 98 99 /// <summary> 100 /// 回滚所有自上次提交以后的修改。 101 /// </summary> 102 void Clear(); 103 104 /// <summary> 105 /// 清空处于persistent in unitofwork状态的实例。 106 /// </summary> 107 TRepository GetRepository<TRepository> () 108 where TRepository : IRepository; 109 } 110 }
基于EntityFramework的工作单元
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Data; 7 using System.Data.Entity; 8 using System.Data.Entity.Infrastructure; 9 10 using Microsoft.Practices.ServiceLocation; 11 12 using Happy.Domain; 13 using Happy.DesignByContract; 14 15 namespace Happy.EntityFramework 16 { 17 /// <summary> 18 /// 基于EntityFramework的工作单元。 19 /// </summary> 20 public abstract class UnitOfWork : DbContext, IUnitOfWork 21 { 22 private readonly Dictionary<Type, IRepository> repositories = new Dictionary<Type, IRepository> (); 23 24 /// <summary> 25 /// 构造方法。 26 /// </summary> 27 protected UnitOfWork() 28 { 29 } 30 31 /// <summary> 32 /// 构造方法。 33 /// </summary> 34 protected UnitOfWork( string nameOrConnectionString) 35 : base (nameOrConnectionString) 36 { 37 } 38 39 /// <inheritdoc /> 40 public bool Contains<TAggregateRoot> (TAggregateRoot item) 41 where TAggregateRoot : AggregateRoot 42 { 43 item.MustNotNull( " item " ); 44 45 return this .Entry(item).State != EntityState.Detached; 46 } 47 48 /// <inheritdoc /> 49 public void Save<TAggregateRoot> (TAggregateRoot item) 50 where TAggregateRoot : AggregateRoot 51 { 52 item.MustNotNull( " item " ); 53 54 this .Set<TAggregateRoot> ().Add(item); 55 } 56 57 /// <inheritdoc /> 58 public void Update<TAggregateRoot> (TAggregateRoot item) 59 where TAggregateRoot : AggregateRoot 60 { 61 item.MustNotNull( " item " ); 62 63 this .Entry(item).State = EntityState.Modified; 64 } 65 66 /// <inheritdoc /> 67 public void Persist<TAggregateRoot> (TAggregateRoot item) 68 where TAggregateRoot : AggregateRoot 69 { 70 item.MustNotNull( " item " ); 71 72 this .Entry(item).State = EntityState.Unchanged; 73 } 74 75 /// <inheritdoc /> 76 public void Delete<TAggregateRoot> (TAggregateRoot item) 77 where TAggregateRoot : AggregateRoot 78 { 79 item.MustNotNull( " item " ); 80 81 this .Entry(item).State = EntityState.Deleted; 82 } 83 84 /// <inheritdoc /> 85 public void Merge<TAggregateRoot> (TAggregateRoot item) 86 where TAggregateRoot : AggregateRoot 87 { 88 item.MustNotNull( " item " ); 89 90 var persistItem = this .Set<TAggregateRoot> ().Find(item.Id); 91 92 this .Entry(persistItem).CurrentValues.SetValues(item); 93 } 94 95 /// <inheritdoc /> 96 public void Evict<TAggregateRoot> (TAggregateRoot item) 97 where TAggregateRoot : AggregateRoot 98 { 99 item.MustNotNull( " item " ); 100 101 this .Entry(item).State = EntityState.Detached; 102 } 103 104 /// <inheritdoc /> 105 public void Flush() 106 { 107 try 108 { 109 base .SaveChanges(); 110 } 111 catch (DbUpdateConcurrencyException ex) 112 { 113 throw new OptimisticConcurrencyException(ex.Message, ex); 114 } 115 } 116 117 public TAggregateRoot Load<TAggregateRoot> (Guid id) 118 where TAggregateRoot : AggregateRoot 119 { 120 return this .Set<TAggregateRoot> ().Find(id); 121 } 122 123 public void Refresh<TAggregateRoot> (TAggregateRoot item) 124 where TAggregateRoot : AggregateRoot 125 { 126 item.MustNotNull( " item " ); 127 128 this .Entry(item).Reload(); 129 } 130 131 /// <inheritdoc /> 132 public void Clear() 133 { 134 base .ChangeTracker.Entries() 135 .ToList() 136 .ForEach(entry => entry.State = System.Data.EntityState.Detached); 137 } 138 139 /// <inheritdoc /> 140 public TRepository GetRepository<TRepository> () 141 where TRepository : IRepository 142 { 143 var key = typeof (TRepository); 144 145 if (! repositories.ContainsKey(key)) 146 { 147 var repository = ServiceLocator.Current.GetInstance<TRepository> (); 148 (repository as IEntityFrameworkRepository).Owner = this ; 149 repositories[key] = repository; 150 } 151 152 return (TRepository)repositories[key]; 153 } 154 } 155 }
备注
其实我们经常忽略一个关于接口的问题,就是异常本身也是API的一部分,虽然这部分在C#中没有办法显式的表达,等我的朋友实现完了NH版本的工作单元的开发,我们就继续对异常进行抽象。
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于准备抽象NHibernate和EntityFramework的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did45522