天天看點

幸福架構:準備抽象NHibernate和EntityFramework,大家給點意見

幸福架構:準備抽象NHibernate和EntityFramework,大家給點意見

背景

考慮到目前中小企業應用的主流是ORM,我準備在NHibernate和EntityFramework之間找到一個抽象層,也就是說我準備隻支援NHibernate和EntityFramework。

思路

NH和EF都實作了“工作單元”和“主鍵映射”這兩種企業應用模式,而這兩種模式其實就是管理一種狀态機,如下圖:

幸福架構:準備抽象NHibernate和EntityFramework,大家給點意見

實作

工作單元接口

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 }      
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 }      

備注

架構位址:http://happy.codeplex.com

繼續閱讀