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&lt;TEntity&gt; 和具体实现GenericRepository&lt;TEntity&gt;,然后使用Ninject 绑定它们:

kernel.Bind(typeof(IGenericRepository<>)).To(typeof(GenericRepository<>));

但是我将如何设置我的IUnitOfWorkUnitOfWork 以确保我的所有存储库共享一个数据库上下文?我一开始就做对了吗?我四处搜索,但似乎只找到了仅使用通用存储库而没有工作单元的教程。

【问题讨论】:

这是我对通用存储库的看法,我的示例项目应该提供更多关于如何实现它的详细信息,实际通用存储库的所有代码都在 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的主要内容,如果未能解决你的问题,请参考以下文章

通用存储库、工作单元、Unity 的架构问题

实体框架使用 Codefirst、通用存储库、工作单元模式保存多对多关系

EF 包括其他实体(通用存储库模式)

csharp EF的通用存储库

具有通用存储库和依赖注入和 SoC 的 EF6 Code First

与 MVC 3、.NET 4.5 和 EF 6 并行获取数据