问题描述
我是MVC3的新手,并且一直在关注asp.net网站上的出色教程.但是,我不太了解如何在Ninject中使用工作单元和通用存储库模式.我以本教程为起点: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/在ASP.NET MVC应用程序中实现存储库和工作单元模式
I'm new to MVC3 and have been following the awesome tutorials on the asp.net website. However, I can't quite wrap my head around how to use Unit of Work and Generic Repository patterns with Ninject. I used this tutorial as a starting point: 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
无需使用接口,我知道可以像这样实现它:
Without using interfaces, I know I can implement it like so:
通用存储库:
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()函数来提交更改.
This setup allows me to pass the same context to all repositories, and then call a single Save() function to commit the changes.
我知道我可以使用接口IGenericRepository<TEntity>
和具体实现GenericRepository<TEntity>
,然后使用Ninject绑定它们:
I know I can use an interface IGenericRepository<TEntity>
and the concrete implementation GenericRepository<TEntity>
and then bind them using Ninject:
kernel.Bind(typeof(IGenericRepository<>)).To(typeof(GenericRepository<>));
但是我将如何设置我的IUnitOfWork
和UnitOfWork
以确保我的所有存储库共享一个数据库上下文?我是否一开始就做对了?我进行了搜索,但似乎只找到了只使用通用存储库而没有工作单元的教程.
But how would I go about setting up my IUnitOfWork
and UnitOfWork
to ensure that all my repositories share a single database context? Am I even doing it right in the first place? I've searched around but all I seem to find are tutorials that only use generic repositories without a unit of work.
推荐答案
您的基本存储库:
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的接口.
Notice Context is an interface implementing UnitOfWork.
您的上下文界面:
public interface IMyContext : IDbContext
{
DbSet<Sometype> SomeProperty { get; set; }
...
}
您的IDbContext接口:
Your IDbContext interface:
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);
}
然后是实际的上下文实现:
Then the actual context implementation:
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配置中只需执行以下操作:
Then in your ninject config you simply do:
kernel.Bind<IUnitOfWork<MyContext>>().To<MyContext>().InRequestScope();
这篇关于MVC3 EF工作单元+通用存储库+ Ninject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!