C# MVC5和x2B;EF+;UOW&x2B;服务层调用SaveChanges()并避免多次访问数据库?
我正在使用:MVC5和EF-Code-First以及存储库和工作单元模式构建一个web应用程序。到目前为止,我有3层:C# MVC5和x2B;EF+;UOW&x2B;服务层调用SaveChanges()并避免多次访问数据库?,c#,design-patterns,asp.net-mvc-5,entity-framework-6,unit-of-work,C#,Design Patterns,Asp.net Mvc 5,Entity Framework 6,Unit Of Work,我正在使用:MVC5和EF-Code-First以及存储库和工作单元模式构建一个web应用程序。到目前为止,我有3层: “数据层”,其中包含存储库UOW “服务层”,参照UOW实现业务逻辑和业务验证 “Web层”,负责通过与服务层通信显示数据 我的域/业务对象在另一个项目中分离。所以基本上我遵循John Papa的结构,除了添加“服务层” 数据/合同/IRepository.cs public interface IRepository<T> where T : class {
- “数据层”,其中包含存储库UOW
- “服务层”,参照UOW实现业务逻辑和业务验证
- “Web层”,负责通过与服务层通信显示数据
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
public interface IUnitOfWork
{
// Save pending changes to the data store.
void Commit();
// Repositories
IRepository<Event> Events { get; }
IRepository<Candidate> Candidates { get; }
}
/// <summary>
/// The EF-dependent, generic repository for data access
/// </summary>
/// <typeparam name="T">Type of entity for this Repository.</typeparam>
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
/// <summary>
/// The "Unit of Work"
/// 1) decouples the repos from the controllers
/// 2) decouples the DbContext and EF from the controllers
/// 3) manages the UoW
/// </summary>
/// <remarks>
/// This class implements the "Unit of Work" pattern in which
/// the "UoW" serves as a facade for querying and saving to the database.
/// Querying is delegated to "repositories".
/// Each repository serves as a container dedicated to a particular
/// root entity type such as a <see cref="Url"/>.
/// A repository typically exposes "Get" methods for querying and
/// will offer add, update, and delete methods if those features are supported.
/// The repositories rely on their parent UoW to provide the interface to the
/// data layer (which is the EF DbContext in this example).
/// </remarks>
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
// Repositories
public IRepository<Student> Students { get { return GetStandardRepo<Event>(); } }
public IRepository<Course> Courses { get { return GetStandardRepo<Course>(); } }
/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.SaveChanges();
}
protected void CreateDbContext()
{
DbContext = new UnicornsContext();
// Do NOT enable proxied entities, else serialization fails
DbContext.Configuration.ProxyCreationEnabled = false;
// Load navigation properties explicitly (avoid serialization trouble)
DbContext.Configuration.LazyLoadingEnabled = false;
// Because Web API will perform validation, I don't need/want EF to do so
DbContext.Configuration.ValidateOnSaveEnabled = false;
}
protected IRepositoryProvider RepositoryProvider { get; set; }
private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}
private UnicornsContext DbContext { get; set; }
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Dispose();
}
}
}
#endregion
}
公共接口i假设,其中T:class
{
IQueryable GetAll();
T GetById(int-id);
无效添加(T实体);
无效更新(T实体);
无效删除(T实体);
无效删除(int-id);
}
数据/合同/IUnitOfWork.cs
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
public interface IUnitOfWork
{
// Save pending changes to the data store.
void Commit();
// Repositories
IRepository<Event> Events { get; }
IRepository<Candidate> Candidates { get; }
}
/// <summary>
/// The EF-dependent, generic repository for data access
/// </summary>
/// <typeparam name="T">Type of entity for this Repository.</typeparam>
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
/// <summary>
/// The "Unit of Work"
/// 1) decouples the repos from the controllers
/// 2) decouples the DbContext and EF from the controllers
/// 3) manages the UoW
/// </summary>
/// <remarks>
/// This class implements the "Unit of Work" pattern in which
/// the "UoW" serves as a facade for querying and saving to the database.
/// Querying is delegated to "repositories".
/// Each repository serves as a container dedicated to a particular
/// root entity type such as a <see cref="Url"/>.
/// A repository typically exposes "Get" methods for querying and
/// will offer add, update, and delete methods if those features are supported.
/// The repositories rely on their parent UoW to provide the interface to the
/// data layer (which is the EF DbContext in this example).
/// </remarks>
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
// Repositories
public IRepository<Student> Students { get { return GetStandardRepo<Event>(); } }
public IRepository<Course> Courses { get { return GetStandardRepo<Course>(); } }
/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.SaveChanges();
}
protected void CreateDbContext()
{
DbContext = new UnicornsContext();
// Do NOT enable proxied entities, else serialization fails
DbContext.Configuration.ProxyCreationEnabled = false;
// Load navigation properties explicitly (avoid serialization trouble)
DbContext.Configuration.LazyLoadingEnabled = false;
// Because Web API will perform validation, I don't need/want EF to do so
DbContext.Configuration.ValidateOnSaveEnabled = false;
}
protected IRepositoryProvider RepositoryProvider { get; set; }
private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}
private UnicornsContext DbContext { get; set; }
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Dispose();
}
}
}
#endregion
}
公共接口IUnitOfWork
{
//将挂起的更改保存到数据存储。
无效提交();
//存储库
i假定事件{get;}
i假定候选者{get;}
}
数据/EFRepository.cs
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
public interface IUnitOfWork
{
// Save pending changes to the data store.
void Commit();
// Repositories
IRepository<Event> Events { get; }
IRepository<Candidate> Candidates { get; }
}
/// <summary>
/// The EF-dependent, generic repository for data access
/// </summary>
/// <typeparam name="T">Type of entity for this Repository.</typeparam>
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
/// <summary>
/// The "Unit of Work"
/// 1) decouples the repos from the controllers
/// 2) decouples the DbContext and EF from the controllers
/// 3) manages the UoW
/// </summary>
/// <remarks>
/// This class implements the "Unit of Work" pattern in which
/// the "UoW" serves as a facade for querying and saving to the database.
/// Querying is delegated to "repositories".
/// Each repository serves as a container dedicated to a particular
/// root entity type such as a <see cref="Url"/>.
/// A repository typically exposes "Get" methods for querying and
/// will offer add, update, and delete methods if those features are supported.
/// The repositories rely on their parent UoW to provide the interface to the
/// data layer (which is the EF DbContext in this example).
/// </remarks>
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
// Repositories
public IRepository<Student> Students { get { return GetStandardRepo<Event>(); } }
public IRepository<Course> Courses { get { return GetStandardRepo<Course>(); } }
/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.SaveChanges();
}
protected void CreateDbContext()
{
DbContext = new UnicornsContext();
// Do NOT enable proxied entities, else serialization fails
DbContext.Configuration.ProxyCreationEnabled = false;
// Load navigation properties explicitly (avoid serialization trouble)
DbContext.Configuration.LazyLoadingEnabled = false;
// Because Web API will perform validation, I don't need/want EF to do so
DbContext.Configuration.ValidateOnSaveEnabled = false;
}
protected IRepositoryProvider RepositoryProvider { get; set; }
private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}
private UnicornsContext DbContext { get; set; }
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Dispose();
}
}
}
#endregion
}
//
///用于数据访问的依赖于EF的通用存储库
///
///此存储库的实体类型。
公共类eRepository:IRepository,其中T:class
{
公共eForepository(DbContext DbContext)
{
if(dbContext==null)
抛出新ArgumentNullException(“dbContext”);
DbContext=DbContext;
DbSet=DbContext.Set();
}
受保护的DbContext DbContext{get;set;}
受保护的DbSet DbSet{get;set;}
公共虚拟IQueryable GetAll()
{
返回DbSet;
}
公共虚拟T GetById(int id)
{
//返回DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate(id));
返回DbSet.Find(id);
}
公共虚拟空添加(T实体)
{
DbEntityEntry DbEntityEntry=DbContext.Entry(实体);
if(dbEntityEntry.State!=EntityState.Distached)
{
dbEntityEntry.State=EntityState.Added;
}
其他的
{
添加(实体);
}
}
公共虚拟无效更新(T实体)
{
DbEntityEntry DbEntityEntry=DbContext.Entry(实体);
if(dbEntityEntry.State==EntityState.Distached)
{
附加数据集(实体);
}
dbEntityEntry.State=EntityState.Modified;
}
公共虚拟作废删除(T实体)
{
DbEntityEntry DbEntityEntry=DbContext.Entry(实体);
if(dbEntityEntry.State!=EntityState.Deleted)
{
dbEntityEntry.State=EntityState.Deleted;
}
其他的
{
附加数据集(实体);
删除(实体);
}
}
公共虚拟无效删除(int-id)
{
var实体=GetById(id);
if(entity==null)返回;//未找到;假设已删除。
删除(实体);
}
}
Data/UnitOfWork.cs
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
public interface IUnitOfWork
{
// Save pending changes to the data store.
void Commit();
// Repositories
IRepository<Event> Events { get; }
IRepository<Candidate> Candidates { get; }
}
/// <summary>
/// The EF-dependent, generic repository for data access
/// </summary>
/// <typeparam name="T">Type of entity for this Repository.</typeparam>
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
/// <summary>
/// The "Unit of Work"
/// 1) decouples the repos from the controllers
/// 2) decouples the DbContext and EF from the controllers
/// 3) manages the UoW
/// </summary>
/// <remarks>
/// This class implements the "Unit of Work" pattern in which
/// the "UoW" serves as a facade for querying and saving to the database.
/// Querying is delegated to "repositories".
/// Each repository serves as a container dedicated to a particular
/// root entity type such as a <see cref="Url"/>.
/// A repository typically exposes "Get" methods for querying and
/// will offer add, update, and delete methods if those features are supported.
/// The repositories rely on their parent UoW to provide the interface to the
/// data layer (which is the EF DbContext in this example).
/// </remarks>
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
// Repositories
public IRepository<Student> Students { get { return GetStandardRepo<Event>(); } }
public IRepository<Course> Courses { get { return GetStandardRepo<Course>(); } }
/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.SaveChanges();
}
protected void CreateDbContext()
{
DbContext = new UnicornsContext();
// Do NOT enable proxied entities, else serialization fails
DbContext.Configuration.ProxyCreationEnabled = false;
// Load navigation properties explicitly (avoid serialization trouble)
DbContext.Configuration.LazyLoadingEnabled = false;
// Because Web API will perform validation, I don't need/want EF to do so
DbContext.Configuration.ValidateOnSaveEnabled = false;
}
protected IRepositoryProvider RepositoryProvider { get; set; }
private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}
private UnicornsContext DbContext { get; set; }
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Dispose();
}
}
}
#endregion
}
//
///“工作单位”
///1)将回购协议与控制器分离
///2)将DbContext和EF与控制器解耦
///3)管理UoW
///
///
///此类实现了“工作单元”模式,其中
///“UoW”用作查询和保存到数据库的门面。
///查询被委托给“存储库”。
///每个存储库充当一个专用于特定存储库的容器
///根实体类型,例如。
///存储库通常公开用于查询和查询的“Get”方法
///将提供添加、更新和删除方法(如果支持这些功能)。
///存储库依靠其父UoW向
///数据层(本例中为EF DbContext)。
///
公共类UnitOfWork:IUnitOfWork,IDisposable
{
公共工作单元(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext=DbContext;
RepositoryProvider=RepositoryProvider;
}
//存储库
公共IRepository学生{get{return GetStandardRepo();}}
公共IRepository课程{get{return GetStandardRepo();}}
///
///将挂起的更改保存到数据库
///
公共无效提交()
{
//System.Diagnostics.Debug.WriteLine(“已提交”);
DbContext.SaveChanges();
}
受保护的void CreateDbContext()
{
DbContext=newunicornscontext();
//不要启用代理实体,否则序列化失败
DbContext.Configuration.ProxyCreationEnabled=false;
//显式加载导航属性(避免序列化问题)
DbContext.Configuration.LazyLoadingEnabled=false;
//因为WebAPI将执行验证,所以我不需要/不希望EF这样做
DbContext.Configuration.ValidateOnSaveEnabled=false;
}
受保护的IRepositoryProvider RepositoryProvider{get;set;}
私有IRepository GetStandardRepo(),其中T:class
{
返回RepositoryProvider.GetRepositoryForEntityType();
}
私有的T GetRepo(),其中T:class
{
返回RepositoryProvider.GetRepository();
}
专用UnicornsContext DbContext{get;set;}
#可识别区域
公共空间处置()
{
处置(真实);
总干事(本);
}
受保护的虚拟void Dispose(bool disposing)
{
如果(处置)
{
if(DbContext!=null)
{
DbContext.Dispose();
}
}
}
#端区
}
然后最后使用Ninject解决依赖关系:
kernel.Bind<RepositoryFactories>().To<RepositoryFactories>().InSingletonScope();
kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
kernel.Bind().To().InSingletonScope();
kernel.Bind().To();
kernel.Bind().To();
我应该在哪里调用UOW.Commit()
,以便重用imple