是种类中有的实际底层操作的落到实处,在开始竞技突然想分享一下那10几年用方式的一点小小的的了解

 

软件开发就像三个世间,而设计情势就是一本高深的秘籍每读3次、用一次、想一次都能博得新的会心,让我们的规划技术有所进步。初始时大家兴许会“为了方式而形式”,让代码变得乱78糟甚至为难令人通晓,但随着布署力量的增加与形式的使用和清楚,稳步地大家或者会遗忘方式随心所欲,此时再读读代码可能你早已发现自个儿的工程已合两为一方式之美—”形式为布置而生,设计为要求而活”。在开赛突然想享受一下那10几年用情势的一点小小的的会心。

  UnifOfWork形式,一般称为“工作单元”情势,是DDD(Domain-Driven
Design,领域驱动设计)的2个组成都部队分,用于在应用服务方法中,控制三个应用服务方法的具备数据库操作,都在四个工作内。近期对个人的3个Web项目展开了改造,根据DDD的设计形式实行了分层,即便在领域层没有实现完全的圈子对象(实体+值对象+领域服务
),可是DDD也并不是铁板一块,架构划设想计指南最后也是要服务于实际项指标,领会思想为笔者所用才是三个抓实的经过,记录下来,以备日后温习。

IRepository 与 IUnitOfWork

在二〇一二年自己曾在Codeproject 发布过题为
The Repository Pattern with EF Code First & Dependency
Injection in ASP.NET
MVC3

的文章,当时描述的是Repository格局和Ioc怎么样构成EF在ASP.NET
MVC3上应用。历时3年多对Repository的行使,近来又有新的清醒。 Repository
是这几年小编用得最多的方式之一,而且也是自身认为最常用和最不难精晓的一种格局,小编动用Repository的目标有二:

  • 将数据的实例化解耦,通过Ioc或是工厂方法组织数据对象而不是用
    “new”
  • 将数据的逻辑行为(CU陆风X8D)解耦,那样会便于自家改换任何款式的数据库,无论底层数据库使用的是MSSQL照旧MongoDB笔者都能够应用相同的走访逻辑。

以下是本身希望在代码中观察的意义

public class PostController:Contrller
{
   private IRepository repository;

   public MyController(IRepository repository){
      this.repository=repository;
   }

   public Action Get(int id) {
     return View(repository.Find(id));
   }

   [HttpPost]
   public Action Create(Post post) {
     repository.Add(post);
     repository.Submit();
     return this.Get(post.ID);
   } 

   ...
}

那边运用了结构注入,由MVC向Controller注入Repository的实例,那样笔者就不要求在使Repository的时候去成立它了。(那种例子你谷歌会发现众多,包蕴在asp.net上也不在少数)

单纯地使用Repository很简单掌握,但利用在项目中的实例处境能够如此吧?当先百分之五十答案是不是认的,就算当前的Controller控制的不只是是多少个实体,而是多少个实体时,假如运用纯Repository的话代码会变糟:

public class PostController:Contrller
{
   private IRepository posts;
   private IRepository blogs;
   private IRepository owners;

   public MyController(IRepository blogs,IRepository posts,IRepository owners){
      this.posts=posts;
      this.blogs=blogs;
      this.owners=owners;
   }

   public Action Get(int id) {
     var post=posts.Find(id)
     var blog=blogs.Find(post.BlogID);
     var owner=posts.Find(post.Owner);
     ...
     return View(new { Post=post, Blog=blog, Owner=owner });
   }


   ...
}

一看起来就好像没什么大标题,只是在协会时多了四个Repository的注入,然则大家的目唯有贰个Controller吗?
而种种实体都亟需去贯彻一个Repository?
那样的写法在项目中传出会怎么着呢?

末尾你会赢得一大堆鸡肋式的”Repository”,他们的形似度尤其大。或是你利用四个Repository完毕拍卖全数的实业,但您必要在布局时展开配置
(注:构造注入并不意味不组织,而是将组织代码放在了3个联结的地点),更糟的状态是,尽管利用的是再而三于IRepository的子接口,那么Controller就会与IRepository的耦合度加大。

很肯定 Repository
不是一种独立的形式,它自个儿和其余形式有很强的相关度,倘使只是拿它来单独行使局限性会一点都不小。大家需求其余的接口去联合“管理”Repository和幸免在Controller内显式的产出Repository的花色注解。将地方的代码改一下:

public class PostController:Contrller
{
   private IUnitOfWorks works;
   public PostController(IUnitOfWorks works){
     this.works=works;
   }
   public Action Get(int id) {
     var post=works.Posts.Find(id)
     var blog=works.Blogs.Find(post.BlogID);
     var owner=works.Posts.Find(post.Owner);
     ...
     return View(new { Post=post, Blog=blog, Owner=owner });
   }

   [HttpPost]
   public Action Create(Post post)
   {
       works.Add(post);
       ...
    }
}

那边就引入了 UnitOfWorks
方式,将对全体的Repository的耦合解决(把具有的Repository变量的扬言去掉了),

IRepository与IUnitOfWorks八个情势是超级结合,大家能够通过对UnitOfWorks多个类举办IoC处理,而调用方代码则汇聚从IUnitOfWorks对象得到所需的Repository,接下去看看她们的概念吧

IRepository 接口

    /// <summary>
    /// 定义通用的Repository接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IRepository<T>: IDisposable
        where T : class
    {
        /// <summary>
        /// 获取所有的实体对象
        /// </summary>
        /// <returns></returns>
        IQueryable<T> All();

/// <summary>
        /// 通过Lamda表达式过滤符合条件的实体对象
        /// </summary>
        IQueryable<T> Filter(Expression<Func<T, bool>> predicate);
/// <summary>
        /// Gets the object(s) is exists in database by specified filter.
        /// </summary>
        bool Contains(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 获取实体总数
        /// </summary>
        int Count();

        int Count(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 通过键值查找并返回单个实体
        /// </summary>
        T Find(params object[] keys);

        /// <summary>
        /// 通过表达式查找复合条件的单个实体
        /// </summary>
        /// <param name="predicate"></param>
        T Find(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 创建实体对象
        /// </summary>
        T Create(T t);

        /// <summary>
        /// 删除实体对象
        /// </summary>
        void Delete(T t);

        /// <summary>
        /// 删除符合条件的多个实体对象
        /// </summary>
        int Delete(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// Update object changes and save to database.
        /// </summary>
        /// <param name="t">Specified the object to save.</param>
        T Update(T t);

        /// <summary>
        /// Clear all data items.
        /// </summary>
        /// <returns>Total clear item count</returns>
        void Clear();

        /// <summary>
        /// Save all changes.
        /// </summary>
        /// <returns></returns>
        int Submit();
    }

 IUnitOfWorks 接口

    public interface IUnitOfWorks
    {
        IQueryable<T> Where<T>(Expression<Func<T, bool>> predicate) where T : class;

        IQueryable<T> All<T>() where T : class;

int Count<T>() where T : class;

        int Count<T>(Expression<Func<T, bool>> predicate) where T : class;

        T Find<T>(object id) where T : class;

        T Find<T>(Expression<Func<T, bool>> predicate) where T : class;

        T Add<T>(T t) where T : class;

        IEnumerable<T> Add<T>(IEnumerable<T> items) where T : class;

        void Update<T>(T t) where T : class;

        void Delete<T>(T t) where T : class;

        void Delete<T>(Expression<Func<T, bool>> predicate) where T : class;

        void Clear<T>() where T : class;

        int SaveChanges();

        void Config(IConfiguration settings);
    }

 

周密一看您会发现IRepository和IUnitOfWorks的定义格外相似,在使用的角度是UnitOfWorks正是全数实例化的Repository的一个统一“包装”,
那是本身在公布 “The Repository Pattern with EF Code First & Dependency
Injection in ASP.NET
MVC3

后对IUnitOfWorks在实用上的一种扩张。在此之前的点子是直接在UnitOfWorks的属性的中暴光无遗三个Repository实例给外部使用,但如此做的话会减低IUnitOfWorks的通用性。所以自身让IUnitOfWorks使用起来更像是二个IRepository.看一段代码的相比:

//之前的做法,Posts是一个IRepository的实现,是不是很像EF
var post=works.Posts.Add(new Post()); //C
works.Posts.Update(post);//U
var post=works.Posts.Get(id); //R
works.Posts.Delete(post);//D

//优化后的IUnitOfWorks
var post=works.Add(new Post());//C
works.Update(post);//U
var post=works.Get(id); //R
works.Delete(post);//D

只要将IRepository通过质量的办法揭穿给调用方,IUnitOfWorks的扩充性就会回落,而且会令IUnitOfWorks的完成类与调用方建立很紧凑的耦合。笔者对IUnitOfWorks优化后以泛型决定选拔哪三个Repository,那样可以将IUnitOfWorks与调用方举办解耦。全部的实业通过一个通用Repository完结,那样可以幸免为每三个实体写一个Repository。而对此持有尤其处理逻辑的Repository才通过品质暴光给调用方。

 

  那样,每一遍Http请求中,因为前后只会有七个UnitOfWork对象,那一个指标里面保存着三个用于工作的对象(EF是DbContext,Dapper是IDBTransaction),在Action甘休的时候,调用UnitOfWork的Commit()方法,进行提交,即完成了各种Controller中只会有多个事务。

小结

 以上述例子为例,倘诺我们想将Category存款和储蓄于文本文件而不想更改调用方的代码。大家能够完结四个FileBaseCategoryRepository,然后在UnitOfWorks在构造后调用Register方法将私下认可的Category
Repository替换掉,同理,那就能够建立分裂的Repository去布署UnitOfWork

 

var works=new UnitOfWorks(new DB());
works.Register(new FileBaseCategoryRepository());

var pc=works.Add(new Category()
{  
   Name="PC",
   Title="电脑"
});

workds.Add(new Product(){
   Category=pc,
   Name="iMac",
   Title="iMac"
   Price=9980
})

works.SaveChanges();

利用IUnitOfWorks+IRepository方式你就足以灵活地布局你的数额访问情势,能够通过Repository不小地提通实体存款和储蓄逻辑代码的重用性。

 

 相关参考

 

贴一个IRepository(领域层中)和它的附和完毕(Repository)

IRepository 与 IUnitOfWorks的实现

在那里作者会先达成一套使用EF访问数据库的通用 Repository 和 UnitOfWorks

EntityRepository 

    public class EntityRepository<TContext, TObject> : IRepository<TObject>
        where TContext : DbContext
        where TObject : class
    {
        protected TContext context;
        protected DbSet<TObject> dbSet;
        protected bool IsOwnContext = false;

        /// <summary>
        /// Gets the data context object.
        /// </summary>
        protected virtual TContext Context { get { return context; } }

        /// <summary>
        /// Gets the current DbSet object.
        /// </summary>
        protected virtual DbSet<TObject> DbSet { get { return dbSet; } }

        /// <summary>
        /// Dispose the class.
        /// </summary>
        public void Dispose()
        {
            if ((IsOwnContext) && (Context != null))
                Context.Dispose();
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Get all objects.
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<TObject> All()
        {
            return  DbSet.AsQueryable();
        }

/// <summary>
        /// Gets objects by specified predicate.
        /// </summary>
        /// <param name="predicate">The predicate object.</param>
        /// <returns>return an object collection result.</returns>
        public virtual IQueryable<TObject> Filter(Expression<Func<TObject, bool>> predicate)
        {
            return  DbSet.Where(predicate).AsQueryable<TObject>();
        }

public bool Contains(Expression<Func<TObject, bool>> predicate)
        {
            return DbSet.Count(predicate) > 0;
        }

        /// <summary>
        /// Find object by keys.
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public virtual TObject Find(params object[] keys)
        {
            return DbSet.Find(keys);
        }

        public virtual TObject Find(Expression<Func<TObject, bool>> predicate)
        {
            return DbSet.FirstOrDefault(predicate);
        }

        public virtual TObject Create(TObject TObject)
        {
            var newEntry = DbSet.Add(TObject);
            if (IsOwnContext)
                Context.SaveChanges();
            return newEntry;
        }

        public virtual void Delete(TObject TObject)
        {
            var entry = Context.Entry(TObject);
            DbSet.Remove(TObject);
            if (IsOwnContext)
                Context.SaveChanges();
        }

        public virtual TObject Update(TObject TObject)
        {
            var entry = Context.Entry(TObject);
            DbSet.Attach(TObject);
            entry.State = EntityState.Modified;
            if (IsOwnContext)
                Context.SaveChanges();
            return TObject;
        }

        public virtual int Delete(Expression<Func<TObject, bool>> predicate)
        {
            var objects = DbSet.Where(predicate).ToList();
            foreach (var obj in objects)
                DbSet.Remove(obj);

            if (IsOwnContext)
                return Context.SaveChanges();
            return objects.Count();
        }

        public virtual int Count()
        {
            return DbSet.Count();
        }

        public virtual int Count(Expression<Func<TObject, bool>> predicate)
        {
            return DbSet.Count(predicate);
        }

        public int Submit()
        {
            return Context.SaveChanges();
        }     

        public virtual void Clear()
        {

        }
    }

 

 UnitOfWorks

public class UnitOfWorks<TDBContext> : IUnitOfWorks
        where TDBContext :DbContext
    {
        protected TDBContext dbContext;

        public UnitOfWorks<TDBContext>(TDBContext context)
        {
             dbContext=context;
        }

        //构造通用的Repository
        private IDictionary<Type,object> repositoryTable = new Dictionary<Type,object>();

        //注册其它的Repository
        public void Register<T>(IRepository<T> repository)
        {
           var key=typeof(T);
           if (repositoryTable.ContainsKey(key))
              repositoryTable[key].Add(repository);
        }


        private IRepository<T> GetRepository<T>()
            where T:class
        {
            IRepository<T> repository = null;
            var key=typeof(T);

            if (repositoryTable.ContainsKey(key))
                repository = (IRepository<T>)repositoryTable[key];
            else
            {
                repository = GenericRepository<T>();
                repositoryTable.Add(key, repository);
            }

            return repository;
        }

        protected virtual IRepository<T> GenericRepository<T>() where T : class
        {
            return new EntityRepository<T>(dbContext);
        }

        public T Find<T>(object id) where T : class
        {
            return GetRepository<T>().Find(id);
        }

        public T Add<T>(T t) where T : class
        {
            return GetRepository<T>().Create(t);
        }

        public IEnumerable<T> Add<T>(IEnumerable<T> items) where T : class
        {
            var list = new List<T>();
            foreach (var item in items)
                list.Add(Add(item));
            return list;
        }

        public void Update<T>(T t) where T : class
        {
            GetRepository<T>().Update(t);
        }

        public void Delete<T>(T t) where T : class
        {
            GetRepository<T>().Delete(t);
        }

        public void Delete<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            GetRepository<T>().Delete(predicate);
        }

        public int SaveChanges(bool validateOnSave = true)
        {
            if (!validateOnSave)
                dbContext.Configuration.ValidateOnSaveEnabled = false;

            return dbContext.SaveChanges();
        }

        public void Dispose()
        {
            if (dbContext != null)
                dbContext.Dispose();
            GC.SuppressFinalize(this);
        }

        public System.Linq.IQueryable<T> Where<T>(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
            where T:class
        {
            return GetRepository<T>().Filter(predicate);
        }

        public T Find<T>(System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T : class
        {
            return GetRepository<T>().Find(predicate);
        }

        public System.Linq.IQueryable<T> All<T>() where T : class
        {
            return GetRepository<T>().All();
        }

        public int Count<T>() where T : class
        {
            return GetRepository<T>().Count();
        }

        public int Count<T>(System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T : class
        {
            return GetRepository<T>().Count(predicate);
        }

        public void Config(IConfiguration settings)
        { 
            var configuration=settings as DbConfiguration ;
            if (configuration != null)
            {
                this.dbContext.Configuration.AutoDetectChangesEnabled = configuration.AutoDetectChangesEnabled;
                this.dbContext.Configuration.LazyLoadingEnabled = configuration.LazyLoadingEnabled;
                this.dbContext.Configuration.ProxyCreationEnabled = configuration.ProxyCreationEnabled;
                this.dbContext.Configuration.ValidateOnSaveEnabled = configuration.ValidateOnSaveEnabled;
            }
        }

        public void Clear<T>() where T : class
        {
            GetRepository<T>().Clear();
        }

        int IUnitOfWorks.SaveChanges()
        {
            return this.SaveChanges();
        }
}

 

 接下来看看哪些采纳那套基于EF的落成,首先是对Model的概念

    public class Category
    {
        [Key]
        public int ID { get; set; }

        public virtual string Name { get; set; }

        public virtual string Title { get; set; }

        public virtual ICollection<Product> Products { get; set; }
    }

    public class Product
    {
        [Key]
        public int ID { get; set; }

        public int CategoryID { get; set; }

        [ForeignKey("CategoryID")]
        public virtual Category Category {get;set;}

        public string Name { get; set; }

        public string Title { get; set; }

        public string Description{get;set;}

        public decimal Price { get; set; }
    }

    public class DB : DbContext
    {
        public DB() : base("DemoDB") { }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
    }

 

调用方:使用UnitOfWorks和Repository

var works=new UnitOfWorks(new DB());

var pc=works.Add(new Category()
{  
   Name="PC",
   Title="电脑"
});

workds.Add(new Product(){
   Category=pc,
   Name="iMac",
   Title="iMac"
   Price=9980
})

works.SaveChanges();

 注:即使急需运用IoC格局组织UnitOfWorks 可参照作者在 “The Repository
Pattern with EF Code First & Dependency Injection in ASP.NET
MVC3

一文中提及怎么样在MVC内经过Unity 达成DI.

  贴二个IService方法和瑟维斯,都在圈子层中

  在ASP.NET
Core的StartUp中,将IUnitOfWork与事实上现类UnitOfwork,进行Scope格局注入。

  因为ASP.NET
Core自带了贰个有益于的IOC容器,能够兑现Transient(每一次使用都成立新的靶子)、Scope(每种Http请求内只创设唯一的对象)、Singletion(单例)二种生命周期的信赖注入,结合ASP.NET的干活原理:对于每2个Http请求,都会实例化二个Controller对其拍卖,因此我们能够开始展览如下设计:

  基础设备层:贰个单身的类库项目:落成了世界层中定义的IRepository,如今已有了EF以及Dapper的二种实现。

  经典的DDD架构,由如图四层组成,第②层是用户层,是一向面向用户的UI界面层,放到开发环境中,能够代替比如浏览器前端、移动端APP、Windows客户端等。第三层是指使用服务层,那层直接面向的是具体的急需,比如某公司的“新职员和工人入职”,这一层依据DDD理论,应该是很薄的一层,重要是构成领域层中的分化对象,来完结最终的现实必要。本文首要落成的UnitOfWork也是在这一层。

  services.AddScoped<IUserRepository, UserRepository>();
  services.AddScoped<IBookRepository, BookRepository>();

    [Route("api/[controller]")]
    public class BusinessController : Controller
    {
        private readonly IAccountService _accountService;
        private readonly IPublishService _publishService;
        private readonly IUnitOfWork _unitOfWork;

        public BusinessController( IPublishService publishService, IAccountService accountService, IUnitOfWork unitOfWork)
        {

            _accountService = accountService;
            _publishService = publishService;
            _unitOfWork = unitOfWork;
        }

         //这里写具体的WebAPI的Action方法,方法中可以调用各种Service中的业务逻辑方法,然后在方法的末尾,加上_unitOfWork.Commit()即可
       
    }

  services.AddScoped<IUnitOfWork,UnitOfWork>();

 

  项目引用(信赖)顺序:最顶层是圈子层,无任何借助;应用访问层(WebAPI)信赖领域层以及基础设备层。

  services.AddScoped<IAccountService, AccountService>();
  services.AddScoped<IPublishService, PublishService>();

一、前言

    public interface IUnitOfWork
    {
        /// <summary>
        /// 事务对象,Dapper为IDbTransaction,EF为DbContext
        /// </summary>
        object VirtualTransaction { get; }

        void Commit();
    }

    public interface IRepository<T> where T:class
    {
        int Insert(T t);

        T Get(string id);

        int Update(T t);

        int Delete(T t);       
    }

 

  第一层领域层,这是一种类统中最基本的一层,表明了业务的逻辑,依照通用语言、和使用通用语言对于业务范围进行限界上下文的撤销合并,划分出一块一块的领域出来,并利用“实体对象、值对象、Repository、领域服务”等概念实行协会。当中Repository应该是空泛的接口,为了然耦合具体的OMuranoM,Repository方式应该是在圈子层定义接口、在第五层基础设备层完毕(以备日后或然的进行更换O帕杰罗M行为)。

然后,我们就足以在Controller中组合不相同Service提供的事务逻辑了,并且能够在同2个作行业内部,有效的增加了事情逻辑层的复用程度还要保障了同一个Http请求内数据的思想政治工作一致性。

  在圈子层中,作者定义如下三种基础接口,当中IUnitOfWork接口包括贰个虚构事务对象、以及三个Commit()方法。IRepository对象用于落到实处对于每一个实体(model可能叫entity都能够)的持久化操作,处于简单时期并不曾投入比如分页查询格局等。

  

 个人的品种范围也十分的小,可是会有“在同样次Http请求内一样业务内整合业务逻辑”的需求,结合ASP.NET的已有功力,分层如下:

  领域层:3个独立的类库项目,定义Model(贫血模型,只含有属性)、服务的接口IXXXService以及其完结XXXService,仓库储存接口IRepository。

  

二 、DDD格局分析

  领域驱动设计是一门高深的文化,以上只简不难单介绍,假使有趣味,能够去看望这两本书: 《领域驱动设计
软件基本复杂性应对之道》《完成世界驱动设计》。

  WebAPI作为整个项目标行使服务层、自个儿没有其它交事务情逻辑,而是结合业务逻辑层中的各个Service,完结具体的求实的用户使用要求。

  用户界面层:Web
SPA(Angular、React等,前端分离另行开发,故VS中不会有有关的档次)

    //领域层中的Book仓储接口,这里简单起见,没有使用更多的接口方法
    public interface IBookRepository:IRepository<Book>
    {

    }

    //基础设施层中使用Dapper操作数据库的实现
    public abstract class BaseRepository
    {

        private readonly IDbTransaction _dbTransaction;

        protected internal IDbConnection DbConnection { get; }


        protected BaseRepository(IUnitOfWork unitOfWork)
        {
            _dbTransaction = (unitOfWork.VirtualTransaction) as IDbTransaction;

            DbConnection = _dbTransaction.Connection;
        }

        public CommandDefinition GenCmd(string cmdText, object paramObj)
        {
            CommandDefinition cmd = new CommandDefinition(cmdText, paramObj, _dbTransaction);

            return cmd;
        }
    }

    public class BookRepository :BaseRepository, IBookRepository
    {


        public BookRepository(IUnitOfWork unitOfWork):base(unitOfWork)
        {

        }

        //这里只写了Insert方法,其他的可类比
        public int Insert(Book t)
        {
            string cmdText = "INSERT INTO Book (Id,BookName,Author,Price,PublishTime) VALUES (@Id,@BookName,@Author,@Price,@PublishTime)";

            var cmd = GenCmd(cmdText, t);

        var result = DbConnection.Execute(cmd);

            return result;
        }

    }

    //另外一个基础设施层项目中,使用EF操作数据库的实现
    public abstract class BaseRepository
    {
        protected internal DbContext DbContext { get; }

        protected BaseRepository(IUnitOfWork unitOfWork)
        {
            DbContext = unitOfWork.VirtualTransaction as DbContext;
        }
    }

    public class BookRepository : BaseRepository ,IBookRepository
    {
        public BookRepository(IUnitOfWork unitOfWork):base(unitOfWork)
        {

        }

        //这里只写了Inert方法,其他的可以类比实现
        public int Insert(Book t)
        {
            DbContext.Book.Add(t);
       //这里不能写DbContext.SaveChanges(),因为EF的SaveChanges()是一个对所有更改的事务性提交,而根据我们的设计事务不在此处提交,而是在应用服务层的Controller中
            return 1;
        }

    }

  //UnitOfWork会被注入到Repo对象中,Repo对象会被注入到Service对象中,Service对象会被注入到Controller对象中

    public interface IPublishService
    {
        void PublishNewBook(Book book);
    }

    public class PublishService : IPublishService
    {
        private readonly IBookRepository _bookRepository;

        public PublishService(IBookRepository bookRepository)
        {
            _bookRepository = bookRepository;
        }

        public void PublishNewBook(Book book)
        {
            _bookRepository.Insert(book);
        }
    }

  好,那时候,应用服务层+UnitOfWork格局的亮点就能够展示出来了。如若是比照守旧三层那样,贰个BLL方法“注册并登记出版物”,他就只好用于“注册并注册出版物”了,不可能落到实处业务逻辑的结合复用。而使用DDD提倡的编制程序形式,就足以兑现三种作业逻辑组合复用,比如本人前边距离的“注册”“登记出版物”那七个世界服务形式,同时还足以构成其余工作逻辑达成更加多区别的有血有肉需求中,比如“注册”+“缴费”、“登记出版物”+“领取津贴”,那里每二个急需都以在同三个作行业内部的,也得以保证数据的一致性。

  第六层基础设备层,是项目中有的切实底层操作的贯彻,比如世界层的Repository的落实,文件的保留,邮件的出殡和埋葬,等等。

 

图片 1

  应用服务层:ASP.NET WebAPI

三 、项目分层简介

  比如叁个具体需若是“2个大小说家,注册成为了作组织员,并注册了他的问世作品”。那么些供给能够拆除为七个工作逻辑:1.注册
2.报了名出版物
。我们在世界层中贯彻了那五个事情逻辑后,就能够在使用访问层(我们的Controller中)进行组合、并在同多个事情进度中决定他们了。有人只怕会问:你如此做,有哪些要求吗,作者直接三层架构那样,Controller调用工作逻辑层BLL中的三个“注册并注册出版物”方法,然后这些BLL方法直接去调用DAL中各类数据库操作方法,不也能够兑现您所说的啊?

再贴一下自家的Controller的表示代码