ASP.NET MVC4+EF系列之七倉儲中的事務實現 實現IUnitOfWork介面

來源:互聯網
上載者:User

很多瞭解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所有,轉載請標明出處

相關關鍵詞:
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.