关系图
一、分层
二、DomainObjects构建edmx
三、EFRepositoryDemo.Domain定义仓储接口
1 public interface IRepository<T> 2 where T : class 3 { 4 void Add(T entity); 5 void AddAll(IEnumerable<T> entities); 6 void Update(T entity); 7 void Update(IEnumerable<T> entities); 8 void Delete(T entity); 9 void Delete(Expression<Func<T, bool>> where); 10 void DeleteAll(IEnumerable<T> entities); 11 12 void Clear(); 13 T GetById(long Id); 14 T GetById(string Id); 15 T Get(Expression<Func<T, bool>> where); 16 IEnumerable<T> GetAll(); 17 IEnumerable<T> GetMany(Expression<Func<T, bool>> where); 18 IEnumerable<T> GetAllLazy(); 19 }
四、Infrastructure层 仓储的抽象基类(EF的CRUD)
Repository很明显的一个特征 是 内部没有SaveChanges()
1 public abstract class EFRepositoryBase<T> where T : class 2 { 3 private Db1DbContext dataContext; 4 private readonly DbSet<T> dbset; 5 6 protected IDatabaseFactory DatabaseFactory 7 { 8 get; 9 private set; 10 } 11 12 protected Db1DbContext DataContext 13 { 14 get { return dataContext ?? (dataContext = DatabaseFactory.Get()); } 15 } 16 17 protected EFRepositoryBase(IDatabaseFactory databaseFactory) 18 { 19 DatabaseFactory = databaseFactory; 20 dbset = DataContext.Set<T>(); 21 } 22 23 public virtual void Add(T entity) 24 { 25 dbset.Add(entity); 26 } 27 28 //新增方法 29 public virtual void AddAll(IEnumerable<T> entities) 30 { 31 dbset.AddRange(entities); 32 } 33 34 public virtual void Update(T entity) 35 { 36 dbset.Attach(entity); 37 dataContext.Entry(entity).State = EntityState.Modified; 38 } 39 40 //新增方法 41 public virtual void Update(IEnumerable<T> entities) 42 { 43 foreach (T obj in entities) 44 { 45 dbset.Attach(obj); 46 dataContext.Entry(obj).State = EntityState.Modified; 47 } 48 } 49 50 public virtual void Delete(T entity) 51 { 52 dbset.Remove(entity); 53 } 54 55 public virtual void Delete(Expression<Func<T, bool>> where) 56 { 57 IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable(); 58 dbset.RemoveRange(objects); 59 } 60 61 //新增方法 62 public virtual void DeleteAll(IEnumerable<T> entities) 63 { 64 dbset.RemoveRange(entities); 65 } 66 67 public virtual void Clear() 68 { 69 throw new NotImplementedException(); 70 } 71 72 public virtual T GetById(long id) 73 { 74 return dbset.Find(id); 75 } 76 77 public virtual T GetById(string id) 78 { 79 return dbset.Find(id); 80 } 81 82 public virtual IEnumerable<T> GetAll() 83 { 84 return dbset.ToList(); 85 } 86 87 public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where) 88 { 89 return dbset.Where(where).ToList(); 90 } 91 92 public T Get(Expression<Func<T, bool>> where) 93 { 94 return dbset.Where(where).FirstOrDefault<T>(); 95 } 96 97 public virtual IEnumerable<T> GetAllLazy() 98 { 99 return dbset; 100 } 101 102 }
五、Repository
1 public interface IStuEducationRepo : IRepository<TB_Stu_Education> 2 { 3 4 }
1 public class StuEducationRepo : RepositoryBase<TB_Stu_Education>, IStuEducationRepo 2 { 3 public StuEducationRepo(IDatabaseFactory databaseFactory) 4 : base(databaseFactory) 5 { 6 7 } 8 9 }
六、工作单元
在进行数据库的CUD操作时,因为Repository内部没有做SaveChanges()操作
所以要增加工作单元,进行包裹
1 public interface IUnitOfWork 2 { 3 void Commit(); 4 void CommitAsync(); 5 }
1 public class UnitOfWork : IUnitOfWork 2 { 3 private readonly IDatabaseFactory databaseFactory; 4 private Db1DbContext dataContext; 5 6 public UnitOfWork(IDatabaseFactory databaseFactory) 7 { 8 this.databaseFactory = databaseFactory; 9 } 10 11 protected Db1DbContext DataContext 12 { 13 get { return dataContext ?? (dataContext = databaseFactory.Get()); } 14 } 15 16 public void Commit() 17 { 18 DataContext.SaveChanges(); 19 } 20 21 public void CommitAsync() 22 { 23 DataContext.SaveChangesAsync(); 24 } 25 26 }
七、Autofac注册
1 var builder = new ContainerBuilder(); 2 builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 3 4 5 builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerLifetimeScope(); 6 builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope(); 7 8 builder.RegisterAssemblyTypes(typeof(StuEducationRepo).Assembly) 9 .Where(t => t.Name.EndsWith("Repo")) 10 .AsImplementedInterfaces().InstancePerLifetimeScope(); 11 12 builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration); 13 IContainer container = builder.Build(); 14 var resolver = new AutofacWebApiDependencyResolver(container); 15 16 // Configure Web API with the dependency resolver. 17 GlobalConfiguration.Configuration.DependencyResolver = resolver;
八、调用示例
1 // GET api/<controller>/5 2 public string Get(int id) 3 { 4 5 var stuAccount = _stuAccountRepo.Get(p => p.UserId == 20987); 6 if (stuAccount != null) 7 { 8 stuAccount.UserName = "张冬林Test"; 9 } 10 11 var stuEducation = _stuEducationRepo.GetMany(p => p.UserId == 20987); 12 if (stuEducation != null && stuEducation.Count() > 0) 13 { 14 foreach (var i in stuEducation) 15 { 16 i.ModifyDate = new DateTime(2016, 06, 14); 17 } 18 } 19 20 _unitOfWork.Commit(); 21 22 return "value"; 23 }
九、总结说明
1、Global Autofac注册,以保证在一次Http请求的生命周期内的DbContext是单例的
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerLifetimeScope();
private Db1DbContext dataContext; public Db1DbContext Get() { return dataContext ?? (dataContext = new Db1DbContext()); }
这样Repository和UnitOfWork的DbContext 是一个对象,即同一个数据库上下文。所以 实现了 CRUD 与 数据持久化 两个步骤的分离
public virtual void Update(T entity) { dbset.Attach(entity); dataContext.Entry(entity).State = EntityState.Modified; }
private readonly IDatabaseFactory databaseFactory; private Db1DbContext dataContext; public UnitOfWork(IDatabaseFactory databaseFactory) { this.databaseFactory = databaseFactory; } protected Db1DbContext DataContext { get { return dataContext ?? (dataContext = databaseFactory.Get()); } } public void Commit() { DataContext.SaveChanges(); }
2、Entity Framework本身就是一仓储,但DDD的这种设计并非画蛇添足。接口定义与代码实现的分离,可以不用关心ORM,可以不用关心是何种DB
附:源码下载