很多瞭解EF的都知道。EF本身的SaveChange()方法是內建事務功能。就是在SaveChange()方法之前的對DbConext的操作都會被當成一個事務去處理。當是在一個架構系統中,SaveChange也許是滿足不了需求的。所以就讓IUnitOfWork的存在提供了必要條件。IUnitOfWork只是一個介面,為我們提供一個規範。至於具體實現各個ORM是不一樣的。當時只要按照這個標準去做我們都是支援的。:)。
/***************************************************** * 作者:egojit * 日期:2012-7-13 * 描述:事務介面 * ***************************************************/namespace EgojitFramework.Domain{ /// <summary> /// 單元工作,為了管理事物 /// </summary> public interface IUnitOfWork { /// <summary> /// /// 返回一個Bool型用於標識單元工作是否被提交 /// </summary> bool Committed { get; } /// <summary> /// 提交單元工作 /// </summary> void Commit(); /// <summary> /// 復原單元工作 /// </summary> void Rollback(); }}
大家可以看到這個借口很簡單,一個屬性用於判定事務是否已經被提交。另外兩個方法就顧名思義,一個提交事務,一個復原事務。
接下來不用說,我們關注他的繼承類和事務是如何去實現的。大家開啟我提供的源碼可以看到它被RepositoryContextManager類繼承。
#region IUnitOfWork 成員 /// <summary> /// 判斷事務是否被提交 /// </summary> public bool Committed { get { return context.Committed; } } /// <summary> ///提交事務 /// </summary> public void Commit() { context.Commit(); } /// <summary> /// 復原事務 /// </summary> public void Rollback() { context.Rollback(); } #endregion
從這段代碼大家看不到任何東西,但是別急。這個我只是和大家分析一個實現過程。而上面的context其實是IRepositoryContext類型。大家開啟這個介面很容易看到它也繼承了IUnitOfWork這會大家忽然明白所有的實現在IRepositoryContext的實作類別中。RepositoryContext類繼承了IRepositoryContext介面,然後我們從代碼中發現關於IUnitOfWork介面的方法歐式抽象的abstract的,那麼它肯定被實現。不難理解其實這個RepositoryContext倉儲環境還只是一般的,而非針對特殊的ORM去實現的。在此我們很容易想到我們這裡的ORM工具是EF那麼它的實現肯定在EntityFrameworkRepositoryContext類中,對了,我們猜測的沒錯。EntityFrameworkRepositoryContext:
public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
我們看到他繼承了RepositoryContext這個類,那我們在回到這個類:
using System;using System.Collections.Generic;using EgojitFramework.Infrastructure;/***************************************************** * 作者:egojit * 日期:2012-7-13 * 描述:倉儲上下文基礎類 * ***************************************************/namespace EgojitFramework.Domain.Repositories{ /// <summary> ///倉儲上下文基礎類 /// </summary> public abstract class RepositoryContext : DisposableObject, IRepositoryContext { #region 私人欄位 private readonly Guid id = Guid.NewGuid(); [ThreadStatic] private readonly Dictionary<Guid, object> newCollection = new Dictionary<Guid, object>(); [ThreadStatic] private readonly Dictionary<Guid, object> modifiedCollection = new Dictionary<Guid, object>(); [ThreadStatic] private readonly Dictionary<Guid, object> deletedCollection = new Dictionary<Guid, object>(); [ThreadStatic] private bool committed = true; #endregion
發現還有這樣一段代碼,他們就是用來放那些,刪除,修改,添加的對象,用GUID作為Key,這個就是本地記憶體,首先將對象的改變都放在這三個集合中。可以看看
RepositoryContext類中對IRepositoryContext介面的實現這裡我就貼其中的一個代碼
/// <summary> /// 註冊一個新的對象到倉儲環境 /// </summary> /// <typeparam name="TAggregateRoot">倉儲根類型.</typeparam> /// <param name="obj">被註冊的對象的名字.</param> public virtual void RegisterNew<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot { if (obj.ID.Equals(Guid.Empty)) throw new ArgumentException("The ID of the object is empty.", "obj"); if (modifiedCollection.ContainsKey(obj.ID)) throw new InvalidOperationException("The object cannot be registered as a new object since it was marked as modified."); if (newCollection.ContainsKey(obj.ID)) throw new InvalidOperationException("The object has already been registered as a new object."); newCollection.Add(obj.ID, obj); committed = false; }
這樣將他們放入字典中。並且 committed = false;再回到EntityFrameworkRepositoryContext類中我們看看事務的實現代碼
/***************************************************** * 作者:egojit * 日期:2012-8-14 * 描述:角色服務 * ***************************************************/using System;using System.Data.Entity;using System.Data.Entity.Validation;using EgojitFramework.Domain.Model;namespace EgojitFramework.Domain.Repositories{ public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext { private readonly EgojitFrameworkContext ctx = new EgojitFrameworkContext(); private readonly object sync = new object(); public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj) { ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Deleted; Committed = false; } public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj) { ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified; Committed = false; } public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj) { ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Added; Committed = false; } public override void Commit() { if (!Committed) { lock (sync) { try { ctx.SaveChanges(); Committed = true; } catch (DbEntityValidationException e) { foreach (var eve in e.EntityValidationErrors) { Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State); foreach (var ve in eve.ValidationErrors) { Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage); } } throw; } } } } public override void Rollback() { Committed = false; }
至此我們瞭解了整個事務的實現過程。這樣實現的事務是不是更加靈活。我們不需要頻繁的去連結資料庫,所有的操作都在本地記憶體。直到我們提交。
著作權:本文屬部落格園和egojit所有,轉載請標明出處