工作单元模式实现

时间:2014-04-16 14:08:02

标签: asp.net-mvc entity-framework

我首先使用ASP.NET MVC和Entity框架代码创建一个应用程序。我正在使用来自以下链接的影响的存储库和工作单元模式。

http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

这里我对工作单元的实现有疑问,因为工作单元是通过直接在类本身中编写实体来实现的。

public class UnitOfWork : IDisposable
{
    private SchoolContext context = new SchoolContext();
    private GenericRepository<Department> departmentRepository;

    public GenericRepository<Department> DepartmentRepository
    {
        get
        {

            if (this.departmentRepository == null)
            {
                this.departmentRepository = new GenericRepository<Department>(context);
            }
            return departmentRepository;
        }
    }

}

您认为实施是否足够好,因为每次添加/删除实体时我都需要更改我的工作单元类。我认为工作单位不应该依赖于实体。因为在我的基于客户反馈的应用程序中,我们将经常添加/删除实体。

我可能听起来很愚蠢,但请告诉我你对此的看法。

3 个答案:

答案 0 :(得分:19)

工作单元模式已在实体框架中实施。

DbContext是你的工作单位。 每个IDbSet都是一个存储库。

using (var context = new SchoolContext())   // instantiate our Unit of Work
{
    var department = context.Departments.Find(id);
}

答案 1 :(得分:8)

UnitOfWorkPattern有几种风格。你所描述的是一个展示一切,也有隐藏一切的方法。在hide方法中,工作单元引用了DbContext.SaveChanges()方法而没有其他内容;听起来像你想要的。

public YourContext : DbContext, IContext{}

public interface IUnitOfWork{
   void Commit();
}

public UnitOfWork : IUnitOfWork{
    private readonly IContext _context;

    //IOC should always inject the same instance of this, register it accordingly
    public UnitOfWork(IContext context){
        _context = context;
    }

    void Commit(){
           // try catch the validation exception if you want to return the validations this
           // way if your confident you've already validated you can put a void here or
           // return the intfrom save changes make sure you handle the disposing properly,
           // not going into that here you also may be doing other stuff here, have multiple
           // "contexts" to save in a single transaction or we have contextProcessors that
           // do stuff based on items in the context
          _context.SaveChanges();
   }
}

如果你没有从UnitOfWork中获取它们,这就留下了如何将你的存储库放入需要它们的类中的问题。这最好由IOC框架处理。这里有两个选项。一次是将UnitOfWork注册为每个请求的单个实例,并将其注入到自定义Repository类中。

public interface IRepository<T>
{
    IQueryable<T> Records();
    //other methods go here
}

public Repository : IRepository<T>
{
    private IContext _context;

    // same instance of context injected into the unit of work, this why when you Commit
    // everything will save, this can get tricky if you start adding Add, Update and stuff
    // but EF does have the support needed.
    public Repository(IContext context)
    {
       _context = context;
    }

    public Records()
    {
        return _context.Set<T>();
    }
}

public class SomeService : ISomeService{
   private readonly _myObjectRepository;

   public SomeService(IRepository<MyObject> myObjectRepository){
       _myObjectRepository = myObjectRepository;
   }
}

我个人认为IDbSet是一个足够的抽象,所以我不再创建存储库。在 为了从上下文中注入IDbSets,您需要将它们注册为您的实例 从您的IOC设置中的上下文中提取。这可能很复杂,取决于你的技能 可能会发现你必须注册我知道你试图避免的每个IDbSet的情况。

使用IDbSet有什么好处,你可以访问像Add这样的简单方法,并且可以避免在一般意义上使用Entity和DbEntity的一些更复杂的部分。

public class SomeService : ISomeService {
    private readonly _myObjectSet;

    // requires specialized IOC configurations because you have to pull this instance from
    // the instance of the context, personally don't know how to do this with a single
    // registration so this has the same problem as having to add each new repository to the
    // unit of work.  In this case each new Entity I add to the context requires I add an IOC
    // registration for the type.

    public SomeService(IDbSet<MyObject> myObjectSet){
        _myObjectSet= myObjectSet;
    }
}

答案 2 :(得分:1)

尝试将SchoolContext传递给GenericRepository:

public GenericRepository<T>
{
    private SchoolContext _context;

    public GenericRepository(SchoolContext context)
    {
       _context = context;
    }

    public Get(int id)
    {
        return _context.Set<T>().Find(id);
    }
}

并使用:

using(var context = new SchoolContext())
{
    var departmentRepository = new GenericRepository<Department>(context);
    var department = departmentRepository.Get(1);
}