MEF實現設計上的“松耦合”

來源:互聯網
上載者:User

標籤:

前言:前篇 C#進階系列——MEF實現設計上的“松耦合”(一) 介紹了下MEF的基礎用法,讓我們對MEF有了一個抽象的認識。當然MEF的用法可能不限於此,比如MEF的目錄服務、目錄篩選、重組組件等進階應用程式在這裡就不做過多講解,因為博主覺得這些用法只有在某些特定的環境下面才會用到,著實不太普遍,感覺沒有鑽下去的必要。如果你有興趣也可以去瞭解下。這篇打算將MEF和倉儲模式結合起來談談MEF在項目中的使用。

 

1、倉儲模式:也叫Repository模式。Repository是一個獨立的層,介於領域層與資料對應層(資料訪問層)之間。它的存在讓領域層感覺不到資料訪問層的存在,它提供一個類似集合的介面提供給領域層進行領域對象的訪問。Repository是倉庫管理員,領域層需要什麼東西只需告訴倉庫管理員,由倉庫管理員把東西拿給它,並不需要知道東西實際放在哪。Repository模式一般是用來封裝資料訪問層的,這也就是為什麼很多地方看到說的什麼“資料倉儲”,大概就是這個意思。Repository模式並不是本文的重點,這裡就不再展開,後面會單獨分享這塊。

關於倉儲模式有以下幾點需要注意:

(1)Repository模式是架構模式,在設計架構時,才有參考價值;

(2)Repository模式使用的意義:一是隔離商務邏輯層和底層資料訪問層,保證資料出入口的唯一性;二是Repository模式針對彙總根設計的,而並不是針對錶和實體設計的,換句話說,使用Repository是為了實現內聚,前端只負責向Repository請求資料即可,而不用關心資料的具體來源;

(3)Repository模式實際用途:更換、升級ORM引擎,不影響商務邏輯;

上面這些東西寫得有點官方。博主的理解是,倉儲模式就是對資料訪問層(或者叫資料對應層)做了一層封裝,每一次前端需要查詢什麼資料或者提交什麼資料的時候,都是通過倉儲對象Repository去操作的,前端基本上感覺不到資料訪問層的存在。這樣說你有沒有好理解一點呢?沒有?好吧,我們來看Demo。

 

2、MEF在倉儲模式上面的應用:由於架構使用的是EF,所以這裡也用EF結合倉儲模式進行講解。為了省略Repository模式的複雜結構,我們僅僅通過倉儲的Save方法來說明。

IRepository<TEntity>介面以及實現代碼:

  public interface IRepository<T>     where T : BaseEntity    {        T Save(T entitiy);    }
  [Export(typeof(IRepository<BaseEntity>))]    public abstract class Repository<T> : IRepository<T> where T : BaseEntity    {        //工作單元        [Import]        protected IUnitOfWork context { set; get; }        private IDbSet<T> _entities;        //註冊MEF        public Repository()        {            Register.regisgter().ComposeParts(this);        }        public virtual T Save(T entitiy)        {            if (entitiy == null) throw new ArgumentException("entitiy nul");            context.Save<T>(entitiy);            return entitiy;        }    }    public static class Register    {        public static CompositionContainer regisgter()        {            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());            var container = new CompositionContainer(catalog);            return container;        }    }

BaseEntity是一個EF實體的公用基類,定義EF實體必須要遵循的約束。

 

IUnitOfWork工作單元介面以及實現

 

  public interface IUnitOfWork : IDisposable    {        int Commit();        void Rollback();        void Save<T>(T entity) where T : BaseEntity;    }
     /// <summary>        /// 單元操作實現        /// </summary>
     [Export(typeof(IUnitOfWork))] public abstract class UnitOfWorkContextBase : IUnitOfWork { [ImportMany] protected abstract IEnumerable<DbContext> Contexts { get; } protected abstract DbContext Cur_context { get; set; } public UnitOfWorkContextBase() {
          Register.regisgter().ComposeParts(this); if (Contexts.Count() <= 0) { throw new Exception(); } Cur_context = Contexts.FirstOrDefault(); } /// <summary> /// 擷取 當前單元操作是否已被提交 /// </summary> public bool IsCommitted { get; private set; } /// <summary> /// 提交當前單元操作的結果 /// </summary> /// <returns></returns> public int Commit() { if (IsCommitted) { return 0; } try { int result = Cur_context.SaveChanges(); IsCommitted = true; return result; } catch (DbUpdateException e) { if (e.InnerException != null && e.InnerException.InnerException is SqlException) { SqlException sqlEx = e.InnerException.InnerException as SqlException; string msg = DataHelper.GetSqlExceptionMessage(sqlEx.Number); throw PublicHelper.ThrowDataAccessException("提交資料更新時發生異常:" + msg, sqlEx); } throw; } } /// <summary> /// 把當前單元操作復原成未提交狀態 /// </summary> public void Rollback() { IsCommitted = false; } public void Dispose() { if (!IsCommitted) { Commit(); } Cur_context.Dispose(); } public void Save<T>(T entity) where T : T { Cur_context.SaveChanges(); } }

既然這裡使用了ImportMany,那麼肯定有一個地方需要Export。我們使用EF建立一個edmx檔案,在產生的內容物件上面加上Export

  [Export(typeof(DbContext))]    public partial class Entities : DbContext    {        public Entities()            : base("name=Entities")        {        }            protected override void OnModelCreating(DbModelBuilder modelBuilder)        {            throw new UnintentionalCodeFirstException();        }            public DbSet<TB_USERS> TB_USERS { get; set; }    }

這裡為什麼要使用ImportMany?前面說了,倉儲的好處之一在於對資料訪問層做封裝,使得前端不比關心資料的具體來源。當我們再建一個資料庫連接的edmx時,我們只需要修改倉儲裡面的Cur_context 這個對象的賦值即可,由於其他地方都是針對Cur_context這一個內容物件做的操作,所以基本都不需要做很大的變化。繞了這麼大一圈,其實博主只是想說明Import和ImportMany和倉儲模式結合使用的好處,至於倉儲模式的適用性問題不是本文的重點。

MEF實現設計上的“松耦合”

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.