使用GenericRepository和MVC 5 / EF实现工作单元

时间:2014-02-19 16:25:59

标签: asp.net-mvc entity-framework repository-pattern unit-of-work

更新3:

我看到这个视频以及作者如何强调使用Repository / UOW ......反对我劝阻的内容。 btw作者正在使用ORM(EF)

http://pluralsight.com/training/Courses/TableOfContents/spa

更新2:

当我在使用存储库时,我需要解决这个问题,而且我不确定我是否正在按照正确的方向行事...... 所以在我的控制器中:

public class PersonsController : Controller
{
    GenericRepository<Person> _genericRepository = new GenericRepository<Person>(new PersonsContext()); 

    public ActionResult Index()
    {
        GenericRepository<Actors> _genericActorRepository = new GenericRepository<Actors>(new PersonsContext());
        IEnumerable<Actors> _actorList = _genericActorRepository.GetAll();
        //IList<Actors> _actorList1 = _genericActorRepository.GetAll().ToList();
        ViewBag.ActorList = new SelectList(_actorList);
        return View(_genericRepository.GetAll());
    }

}

更新:

以下是Microsoft Developer Network关于GenericRepository的讨论的link

我正在尝试在系统的设计阶段实施最佳实践。我将使用实体框架,ASP.NET MVC 5 C#和通用存储库/工作模式单元(希望如此)。

我的问题:如何在我的GenericRepository中引入工作单元?

这是我的GenericRepository类:

public interface IGenericRepository<TEntity> : IDisposable
{
    Task<TEntity> GetByIdAsync(int id);        
    IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate);
    IQueryable<TEntity> GetAll();
    Task EditAsync(TEntity entity);
    Task InsertAsync(TEntity entity);
    Task DeleteAsync(TEntity entity);
}  

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    protected DbSet<TEntity> _dbSet;
    private readonly DbContext _dbContext;

    public GenericRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
        _dbSet = _dbContext.Set<TEntity>();
    }

    public GenericRepository() {}

    public IQueryable<TEntity> GetAll()
    {
        return _dbSet;
    }

    public async Task<TEntity> GetByIdAsync(int id)
    {
        return await _dbSet.FindAsync(id);
    }

    public IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate)
    {
        return _dbSet.Where(predicate);
    }

    public async Task EditAsync(TEntity entity)
    {
        _dbContext.Entry(entity).State = EntityState.Modified;
        await _dbContext.SaveChangesAsync();
    }

    public async Task InsertAsync(TEntity entity)
    {

        _dbSet.Add(entity);
        await _dbContext.SaveChangesAsync();
    }

    public async Task DeleteAsync(TEntity entity)
    {
        //if (context.Entry(entityToDelete).State == EntityState.Detached)
        //{
        //    dbSet.Attach(entityToDelete);
        //}
        _dbSet.Remove(entity);
        await _dbContext.SaveChangesAsync();
    }

    public void Dispose(bool disposing)
    {
        if (_dbContext != null)
        {
            _dbContext.Dispose();
        }
        GC.SuppressFinalize(this);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

模特课程:

public class Person
{
    public int Id { get; set; }
    public String Fullname { get; set; }
    public String Profession { get; set; }
    public int Age { get; set; }
}

上下文

public class PersonsContext : DbContext
{
    public PersonsContext() : base("name=PersonsContext")
    {
    }
    public DbSet<Person> People { get; set; }
}

控制器:

public class PersonsController : Controller
{
    GenericRepository<Person> _genericRepository = new GenericRepository<Person>(new PersonsContext()); 
    //
    // GET: /Persons/
    public ActionResult Index()
    {
        return View(_genericRepository.GetAll());
    }

    //
    // GET: /Persons/Details/5
    public async Task<ActionResult> Details(Int32 id)
    {
        Person person = await _genericRepository.GetByIdAsync(id);
        if (person == null)
        {
            return HttpNotFound();
        }
        return View(person);
    }

    //
    // GET: /Persons/Create
    public ActionResult Create()
    {
        return View();
    }

    //
    // POST: /Persons/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Create(Person person)
    {
        if (ModelState.IsValid)
        {
            await _genericRepository.InsertAsync(person);
            return RedirectToAction("Index");
        }

        return View(person);
    }

    //
    // GET: /Persons/Edit/5
    public async Task<ActionResult> Edit(Int32 id)
    {
        Person person = await _genericRepository.GetByIdAsync(id);
        if (person == null)
        {
            return HttpNotFound();
        }
        return View(person);
    }

    //
    // POST: /Persons/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Edit(Person person)
    {
        if (ModelState.IsValid)
        {
            await _genericRepository.EditAsync(person);
            return RedirectToAction("Index");
        }
        return View(person);
    }
}

4 个答案:

答案 0 :(得分:9)

在我看来,这已成为一种反模式。使用工作单元和存储库是重要且良好的设计,大多数人忽视了实体框架已经是工作单元和通用存储库的实现这一事实。

如果您确实认为有必要(例如,您打算支持不同类型的数据访问),或者您认为您的应用程序将会特别长久并且需要大量持续时间,那么只能在EF上实现您自己的UoW和通用存储库保养。如果您的应用程序相对简单,和/或不太可能发生重大变化,那么就没有理由实施其他抽象。

我不建议在控制器中直接使用EF代码,因此您应该使用某种数据抽象,例如服务层或具体存储库(与通用相反,具体存储库具有{{1}等方法将业务逻辑抽象为方法)。

实现自己的UoW或Generic Repository的另一个原因是,如果您不打算使用支持UoW的ORM,那么您需要自己的实现。

答案 1 :(得分:1)

我认为通过实体框架对通用存储库进行分层通常是一种反模式。实体框架您的通用存储库,它已经实现了工作单元模式。在我自己的代码中,我跳过“存储库”层(因为我使用EF),而是直接从我的控制器调用EF代码,或者如果逻辑很复杂或需要在多个地方使用,我将在EF的顶部添加一个服务层,它具有实际的业务逻辑(即,如果你添加'x',你总是需要'y'来配合它,那样的事情)。 MVC代码 - 以及来自其他地方的代码 - 然后将调用服务层,但服务层不是,也不能是通用的。

您有时使用在EF上实现通用存储库的原因是为了可测试性 - 模拟自己的通用存储库比模拟EF要容易得多。但是现在,EF是相当可以嘲笑的 - 请不要嗤之以鼻 - 只要你对你的Include()陈述以及其他一些问题一直保持谨慎。

答案 2 :(得分:1)

通常,避免在您的代码中包含不必要的抽象,因为您在某处读取了最佳实践。 如果你无法证明抽象的合理性,你最好避免它们。您可以稍后轻松地重构代码并根据需要添加任意数量的层。 如果你的答案是,那么过度使你的实现复杂化是一个坏主意,也许我将来需要

答案 3 :(得分:1)

public class UnitOfWork
{
    private DbContext _dbContext = new MyNameSpace.MyDbContext();
    private readonly bool _readOnly;

    public UnitOfWork(bool readOnly = false)
    {
        _readOnly = readOnly;
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }

    internal DbContext GetDbContext()
    {
        return _dbContext;
    }

    internal bool ReadOnly
    {
        get
        {
            return _readOnly;
        }
    }
}

此外,通用存储库如:

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    private DbSet<TEntity> _dbSet;
    private DbQuery<TEntity> _dbQuery;
    private readonly DbContext _dbContext;

    public GenericRepository(UnitOfWork unitOfWork)
    {
        _dbContext = unitOfWork.GetDbContext();
        _dbSet = _dbContext.Set<TEntity>();
        if (unitOfWork.ReadOnly)
        {
            _dbQuery = _dbSet.AsNoTracking();
        }
        else
        {
            _dbQuery = _dbSet;
        }
    }

    public GenericRepository()
    {
    }

    public IQueryable<TEntity> GetAll()
    {
        return _dbQuery;
    }

    public async Task<TEntity> GetByIdAsync(int id)
    {
        return await _dbSet.FindAsync(id);
    }

    public IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate)
    {
        return _dbQuery.Where(predicate);
    }

    public async Task EditAsync(TEntity entity)
    {
        _dbContext.Entry(entity).State = EntityState.Modified;
        await _dbContext.SaveChangesAsync();
    }

    public async Task InsertAsync(TEntity entity)
    {
        _dbSet.Add(entity);
        await _dbContext.SaveChangesAsync();
    }

    public async Task DeleteAsync(TEntity entity)
    {
        _dbSet.Remove(entity);
        await _dbContext.SaveChangesAsync();
    }
}

如果您稍后决定要使用轻量级ORM,则不会粘在它上面。

您可以将IQueryable引用迁移到存储库中不紧密耦合的特定方法,并将EF生成的SQL移植到轻量级ORM,或者直接指向您喜欢的ADO.Net。