DDD领域驱动之干货(三)完结篇!
首先这里发一下结构图,因为是重写的,但是代码都是一样所有如下:
这里我先说一下看了大部分的DDD文章都是采用的WCF做服务,这里呢我用的是webapi做服务,WCF和WEBAPI的区别可以去百度下。
好了。现在我们看下automapper的具体实现。
因为automapper又一个Profile类,而我们自己写的类去继承这个类,所有如下图:
上图是创建映射关系,下面就去添加映射
这些做完了 我们现在需要使用
这里的dto类型是CostomDTO 也就是数据传输对象。
下面我们来看下工作单元,下面我直接贴代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.UnitOfWork { /// <summary> /// 表示所有集成该接口都是工作单元的一种实现 /// </summary> public interface IUnitOfWork { /// <summary> /// 提交 /// </summary> void Commit(); /// <summary> /// 异步提交 /// </summary> /// <returns></returns> Task CommitSyncAsync(); /// <summary> /// 回滚 /// </summary> void Rollback(); /// <summary> /// 已经提交过了 /// </summary> bool Committed { get; } /// <summary> /// 事务支持 /// </summary> //bool DistributedTransactionSupported { get; } } }
这是IUnitOfWork接口代码。
using KuRuMi.Mio.DoMainModel.BaseModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.UnitOfWork { public interface IUnitOfWorkContext : IUnitOfWork, IDisposable { /// <summary> /// 将指定的聚合根标注为“新建”状态。 /// </summary> /// <typeparam name="TAggregateRoot">需要标注状态的聚合根类型。</typeparam> /// <param name="obj">需要标注状态的聚合根。</param> void RegisterNew<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot; /// <summary> /// 将指定的聚合根标注为“更改”状态。 /// </summary> /// <typeparam name="TAggregateRoot">需要标注状态的聚合根类型。</typeparam> /// <param name="obj">需要标注状态的聚合根。</param> void RegisterModified<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot; /// <summary> /// 将指定的聚合根标注为“删除”状态。 /// </summary> /// <typeparam name="TAggregateRoot">需要标注状态的聚合根类型。</typeparam> /// <param name="obj">需要标注状态的聚合根。</param> void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot; } }
这是IUnitOfWorkContext接口代码
因为我是基于EF实现的所以这里多了一层EF的工作单元代码
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.UnitOfWork { /// <summary> /// 表示是EF仓储的一种实现 /// </summary> public interface IEFUnitOfWorkContext : IUnitOfWorkContext { DbContext Context { get; } } }
完成这里接下来就是工作单元的实现类
using KuRuMi.Mio.DoMainModel.BaseModel; using KuRuMi.Mio.DoMain.Infrastructure; using KuRuMi.Mio.DoMain.Repository.EFRepository; using KuRuMi.Mio.DoMain.Repository.UnitOfWork; using System.Data.Entity; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.BaseUnitOfWork { public class UnitOfWorkContext: DisposableObject, IEFUnitOfWorkContext { private KurumiMioDbContext kurumi = null; public UnitOfWorkContext() { kurumi = new KurumiMioDbContext(); } public DbContext Context { get { return kurumi; } } #region 工作单元 public bool Committed { get; protected set; } /// <summary> /// 同步提交 /// </summary> public void Commit() { if (!Committed) { //kurumi.Value.GetValidationErrors(); Context.SaveChanges(); Committed = true; } } /// <summary> /// 异步提交 /// </summary> /// <returns></returns> public async Task CommitSyncAsync() { if (!Committed) { await Context.SaveChangesAsync(); Committed = true; } } /// <summary> /// 释放资源 /// </summary> /// <param name="disposing"></param> protected override void Dispose(bool disposing) { if (disposing) { if (!Committed) Commit(); Context.Dispose(); kurumi.Dispose(); } } /// <summary> /// 回滚 /// </summary> public void Rollback() { Committed = false; } #endregion #region IEFUnitOfWorkContext接口 /// <summary> /// 删除未提交 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="obj"></param> public void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot { Context.Entry(obj).State = EntityState.Deleted; Committed = false; } /// <summary> /// 修改未提交 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="obj"></param> public void RegisterModified<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot { if (Context.Entry(obj).State == EntityState.Detached) { Context.Set<TAggregateRoot>().Attach(obj); } Context.Entry(obj).State = EntityState.Modified; Committed = false; } /// <summary> /// 新建未提交 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="obj"></param> public void RegisterNew<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot { var state = Context.Entry(obj).State; if (state == EntityState.Detached) { Context.Entry(obj).State = EntityState.Added; } Committed = false; } #endregion } }
现在呢就是我的仓储,因为是聚合根的缘故,所以聚合后的根有自己特有的仓储代码如下。
using KuRuMi.Mio.DoMainModel.Model; using KuRuMi.Mio.DoMainModel.Repositories; using KuRuMi.Mio.DoMain.Repository.EFRepository; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.ModelRepository { public class CostomRepositoryImpl :RepositoryImpl<Costom>, ICostomRepository { public KurumiMioDbContext context => lazy.Context as KurumiMioDbContext; public Costom GetAll() { string sql = "select * from Costom"; return context.costom.SqlQuery(sql).FirstOrDefault(); } } }
然后是我的总仓储的实现
using KuRuMi.Mio.DoMainModel.BaseModel; using KuRuMi.Mio.DoMainModel.Repositories; using KuRuMi.Mio.DoMain.Repository.BaseUnitOfWork; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.EFRepository { /// <summary> /// 仓储的泛型实现 /// </summary> /// <typeparam name="TEntity"></typeparam> public class RepositoryImpl<TEntity> : IRepository<TEntity> where TEntity : AggregateRoot { public readonly UnitOfWorkContext lazy = null; public RepositoryImpl() { lazy = new UnitOfWorkContext(); } /// <summary> /// 新增 /// </summary> /// <param name="aggregateRoot"></param> public virtual void Add(TEntity aggregateRoot) { lazy.RegisterNew<TEntity>(aggregateRoot); lazy.Commit(); } /// <summary> /// 通过key获取聚合根 /// </summary> /// <param name="key"></param> /// <returns></returns> public virtual TEntity GetKey(Guid key) { return lazy.Context.Set<TEntity>().Find(key); } public virtual IQueryable<TEntity> LoadAll(Expression<Func<TEntity, bool>> predicate) { return lazy.Context.Set<TEntity>().Where(predicate).AsQueryable(); } /// <summary> /// 复杂查询 /// </summary> /// <param name="sql"></param> /// <returns></returns> public virtual IQueryable<TEntity> LoadForSql(string sql) { return lazy.Context.Set<TEntity>().SqlQuery(sql).AsQueryable(); } public virtual IEnumerable<TEntity> LoadListAll(Expression<Func<TEntity, bool>> predicate) { return lazy.Context.Set<TEntity>().Where(predicate).ToList(); } /// <summary> /// 复杂查询 /// </summary> /// <param name="sql"></param> /// <returns></returns> public virtual IEnumerable<TEntity> LoadListForSql(string sql) { return lazy.Context.Set<TEntity>().SqlQuery(sql).ToList(); } /// <summary> /// 删除 /// </summary> /// <param name="aggregateRoot"></param> public virtual void Remove(TEntity aggregateRoot) { lazy.RegisterDeleted<TEntity>(aggregateRoot); lazy.Commit(); } /// <summary> /// 修改 /// </summary> /// <param name="aggregateRoot"></param> public virtual void Update(TEntity aggregateRoot) { lazy.RegisterModified<TEntity>(aggregateRoot); lazy.Commit(); } } }
现在回到我们的服务层
系统初始化我采用的是autofac,至于为什么不采用unity,博主个人喜欢用autofac原因轻量,简单。
好了下面献上我的初始化系统类。
using KuRuMi.Mio.DataObject.AutoMapperDTO; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using KuRuMi.Mio.DoMain.Infrastructure.IocManager; using KuRuMi.Mio.DoMainModel.Repositories; using Autofac; namespace KuRuMi.Mio.BootStarp { /// <summary> /// 系统初始化 /// </summary> public class OptionBootStarp { protected IEnumerable<Assembly> assembles { get; } protected IIocManager ioc { get; } public OptionBootStarp(IEnumerable<Assembly> ass) { assembles = ass; ioc = IocManager.Instance; } protected IEnumerable<Type> Repository => assembles.SelectMany(a => a.ExportedTypes.Where(t => t.GetInterfaces().Contains(typeof(IBaseRepository)))); protected IEnumerable<Type> BaseDTO => assembles.SelectMany(a => a.ExportedTypes.Where(t => t.GetInterfaces().Contains(typeof(IAutoMapper)))); protected IEnumerable<Type> Services => assembles.SelectMany(a => a.ExportedTypes.Where(t => t.GetInterfaces().Contains(typeof(IService)))); /// <summary> /// 预加载 /// </summary> public void Initialize() { //加载所有DTO BaseDTO.ToList().ForEach(s=> { var dtpye= Activator.CreateInstance(s) as IAutoMapper; ioc.build.RegisterInstance(dtpye).As<MapperConfigurationImpl>().SingleInstance().PropertiesAutowired(); }); //加载所有的仓储 Repository.ToList().ForEach(s => { if (s.IsClass == true && s.IsGenericType == false) { var dtpye = Activator.CreateInstance(s); ioc.build.RegisterType(dtpye.GetType()).As(dtpye.GetType()); } }); //加载所有服务 Services.ToList().ForEach(s => { if (s.IsClass == true) { var stype = Activator.CreateInstance(s); ioc.build.RegisterType(stype.GetType()).As(stype.GetType()); } }); PostInit(); } /// <summary> /// 注入 /// </summary> protected void PostInit() { ioc.CompleteBuild(); } } }
下面贴上测试结果,WEB端请求的是webapi其中涉及到跨域请求问题,采用的是微软的cors包。
需要代码的同学点这里。
PS:采用了autofac IOC框架 automapper 映射框架 Log4Net 日志 ORM是EF 用的是codefirst 运行的时候只需要改web.config的数据库连接就可以了。
链接: 百度 密码: 3baw