MVC3 EF 工作单元 + 通用存储库 + Ninject
Posted
技术标签:
【中文标题】MVC3 EF 工作单元 + 通用存储库 + Ninject【英文标题】:MVC3 EF Unit of Work + Generic Repository + Ninject 【发布时间】:2012-08-11 08:24:19 【问题描述】:我是 MVC3 的新手,一直在关注 asp.net 网站上的精彩教程。但是,我不能完全理解如何将工作单元和通用存储库模式与 Ninject 一起使用。我以本教程为起点:http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
不使用接口,我知道我可以这样实现:
通用存储库:
public class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
internal MyContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(MyContext context)
this.context = context;
this.dbSet = context.Set<TEntity>();
工作单元:
private MyContext context = new MyContext();
private GenericRepository<Student> studentRepository;
private GenericRepository<Course> courseRepository;
public GenericRepository<Student> StudentRepository
if (this.studentRepository == null)
this.studentRepository = new GenericRepository<Student>(context);
return studentRepository;
public GenericRepository<Course> CourseRepository
if (this.courseRepository == null)
this.courseRepository = new GenericRepository<Course>(context);
return courseRepository;
此设置允许我将相同的上下文传递给所有存储库,然后调用单个 Save() 函数来提交更改。
我知道我可以使用接口IGenericRepository<TEntity>
和具体实现GenericRepository<TEntity>
,然后使用Ninject 绑定它们:
kernel.Bind(typeof(IGenericRepository<>)).To(typeof(GenericRepository<>));
但是我将如何设置我的IUnitOfWork
和UnitOfWork
以确保我的所有存储库共享一个数据库上下文?我一开始就做对了吗?我四处搜索,但似乎只找到了仅使用通用存储库而没有工作单元的教程。
【问题讨论】:
这是我对通用存储库的看法,我的示例项目应该提供更多关于如何实现它的详细信息,实际通用存储库的所有代码都在 github 上。 blog.staticvoid.co.nz/2011/10/… @LukeMcGregor 感谢您的链接!您的博客文章和代码确实帮助我更了解这一切。谢谢! 这里是generic repositories的替代实现。 又一个利用存储库、工作单元和规范模式的好例子:huyrua.wordpress.com/2010/07/13/… 【参考方案1】:你的基础回购:
public class BaseRepository<TObject> : IRepository<TObject>
where TObject : class
public BaseRepository(IUnitOfWork unitOfWork)
if (unitOfWork == null) throw new ArgumentException("unitOfWork");
UnitOfWork = unitOfWork;
protected DbSet<TObject> DbSet
get
return Context.Set<TObject>();
public void Dispose()
if (sharedContext && (Context != null))
Context.Dispose();
public virtual IQueryable<TObject> All()
return DbSet.AsQueryable();
public virtual IQueryable<TObject>
Filter(Expression<Func<TObject, bool>> predicate)
return DbSet.Where(predicate).AsQueryable<TObject>();
public virtual IQueryable<TObject> Filter<Key>(Expression<Func<TObject, Key>> sortingSelector, Expression<Func<TObject, bool>> filter, out int total,
SortingOrders sortby = SortingOrders.Asc, int index = 0, int size = 50)
int skipCount = index * size;
var _resultSet = filter != null ? DbSet.Where(filter).AsQueryable() : DbSet.AsQueryable();
total = _resultSet.Count();
_resultSet = sortby == SortingOrders.Asc ? _resultSet.OrderBy(sortingSelector).AsQueryable() : _resultSet.OrderByDescending(sortingSelector).AsQueryable();
_resultSet = skipCount == 0 ? _resultSet.Take(size) : _resultSet.Skip(skipCount).Take(size);
return _resultSet;
public bool Contains(Expression<Func<TObject, bool>> predicate)
return DbSet.Count(predicate) > 0;
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, bool SaveChanges = true)
var newEntry = DbSet.Add(TObject);
if (!sharedContext && SaveChanges)
Context.SaveChanges();
return newEntry;
public virtual int Count
get
return DbSet.Count();
public virtual int Delete(TObject TObject)
DbSet.Remove(TObject);
if (!sharedContext)
return Context.SaveChanges();
return 0;
public virtual int Update(TObject TObject, bool SaveChanges = true)
var entry = Context.Entry(TObject);
DbSet.Attach(TObject);
entry.State = EntityState.Modified;
if (!sharedContext && SaveChanges)
return Context.SaveChanges();
return 0;
public virtual int Delete(Expression<Func<TObject, bool>> predicate)
var objects = Filter(predicate);
foreach (var obj in objects)
DbSet.Remove(obj);
if (!sharedContext)
return Context.SaveChanges();
return 0;
/// <summary>
/// Sets the state of an entity.
/// </summary>
/// <param name="entity">object to set state.</param>
/// <param name="entityState"><see cref="EntityState"/></param>
protected virtual void SetEntityState(object entity, EntityState entityState)
Context.Entry(entity).State = entityState;
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
protected virtual void Attach(object entity)
if (Context.Entry(entity).State == EntityState.Detached)
Context.Entry(entity).State = EntityState.Modified;
protected virtual void Detach(object entity)
Context.Entry(entity).State = EntityState.Detached;
public void SubmitChanges()
UnitOfWork.SaveChanges();
#region Properties
private bool sharedContext get; set;
/// <summary>
/// Unit of work controlling this repository.
/// </summary>
protected IUnitOfWork UnitOfWork get; set;
/// <summary>
/// Provides access to the ef context we are working with
/// </summary>
internal IMyContext Context
get
return (IMyContext)UnitOfWork;
#endregion
Notice Context 是一个实现 UnitOfWork 的接口。
你的上下文界面:
public interface IMyContext : IDbContext
DbSet<Sometype> SomeProperty get; set;
...
你的 IDbContext 接口:
public interface IDbContext
DbChangeTracker ChangeTracker get;
DbContextConfiguration Configuration get;
Database Database get;
void Dispose();
void Dispose(bool disposing);
DbEntityEntry Entry(object entity);
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
bool Equals(object obj);
int GetHashCode();
Type GetType();
IEnumerable<DbEntityValidationResult> GetValidationErrors();
void OnModelCreating(DbModelBuilder modelBuilder);
int SaveChanges();
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(Type entityType);
bool ShouldValidateEntity(DbEntityEntry entityEntry);
string ToString();
DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items);
然后是实际的上下文实现:
public class MyContext : DbContext, IUnitOfWork, IMyContext
//public MyContext()
//
// Database.SetInitializer<ReconContext>(null);
//
public ReconContext()
: base("Name=ReconContext")
((IObjectContextAdapter)this).ObjectContext.ContextOptions.ProxyCreationEnabled = false;
public DbSet<SomeType> SomeProperty get; set;
....
public new void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Configurations.Add(new SomePropertyMap());
.....
base.OnModelCreating(modelBuilder);
int IUnitOfWork.SaveChanges()
return base.SaveChanges();
void IDisposable.Dispose()
base.Dispose();
public new void Dispose(bool disposing)
base.Dispose(disposing);
public new bool ShouldValidateEntity(DbEntityEntry entityEntry)
return base.ShouldValidateEntity(entityEntry);
public new DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
return base.ValidateEntity(entityEntry, items);
然后在您的 ninject 配置中,您只需执行以下操作:
kernel.Bind<IUnitOfWork<MyContext>>().To<MyContext>().InRequestScope();
【讨论】:
以上是关于MVC3 EF 工作单元 + 通用存储库 + Ninject的主要内容,如果未能解决你的问题,请参考以下文章
实体框架使用 Codefirst、通用存储库、工作单元模式保存多对多关系