關系圖
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 }
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 }
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 }
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
附:源碼下載