C#进阶系列——MEF实现设计上的“松耦合”(二)

2016-4-1 | 发布者:DotNet

(点击上方蓝字,可快速关注我们)


来源:懒得安分

链接:http://www.cnblogs.com/landeanfen/p/4760740.html


前言:前篇 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和仓储模式结合使用的好处,至于仓储模式的适用性问题不是本文的重点。

【今日微信公号推荐↓】


更多推荐请看值得关注的技术和设计公众号


其中推荐了包括技术设计极客 和 IT相亲相关的热门公众号。技术涵盖:Python、Web前端、Java、安卓、iOS、PHP、C/C++、.NET、Linux、数据库、运维、大数据、算法、IT职场等。点击《值得关注的技术和设计公众号》,发现精彩!



音乐节详情,请点阅读原文



热门文章

更多

私房话

三年后,这可能会是大部分人离婚的原因..

三年后,这可能会是大部分人离婚的原因..

或许以后离婚的原因并不是婚外情,而是···吃饭的时候,就算对方在你面前,你依旧不停地微信,刷屏,自拍,心不在焉!看别人不停的摆弄手机,自己也情不自禁拿起手机,为的只是缓解尴尬气氛。夫妻之间懒得交流...
女人那点事 • 
女人别傻了,看看男人内心潜规则吧!

女人别傻了,看看男人内心潜规则吧!

男人说不在乎女人外表,纯粹的鬼话  男人说白了就是视觉动物,男人们在一起讨论的绝对少不了女人,而且基本是在讨论哪个女人身材好,哪个女人漂亮,哪个女人容易追。男人会说其实外貌是其次关键还是在于内心,...
教你看穿男人心 • 
男人从二奶脚一直亲到胸,妻子看后泪流满面..

男人从二奶脚一直亲到胸,妻子看后泪流满面..

男人和女人准备结婚, 男人有15万,女人有10万。男人在婚前用15万付了首付,女的用10万装修房子并购买家电。婚后,男的每月工资3000元还贷,剩余1000元。女的每月工资3000元,男女一起养家。3年以后,女的怀孕了...
懂点男人女人 • 
世间的所有情感,都是一种仪式

世间的所有情感,都是一种仪式

仪式就是要告诉对方,我记得你,我在乎你,我需要你。1我有个朋友他家四世同堂,逢年过节他都必发一条朋友圈,照片就是一大家子人坐一块儿吃饭。而配上的文字肯定是XX节,家族聚餐,必须得是太奶奶的手艺!冬菇...
情感心理学 • 
女人10大面相特点,注定这辈子大富大贵

女人10大面相特点,注定这辈子大富大贵

大多数人们认为手指越细长越好看。一个女人如果拥有纤细修长的手指,财运通常不会太差,不用太过操心就能过上好日子。对男人而言,较小的手部和匀称的的手型反而能带来大量财富。如果手部肤色微红,更是大富的象...
爱情魔方 • 
加载更多