工作单元模式实现

Jal*_*ama 12 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净MVC应用程序

在这里,我对工作单元的实现存在疑问,该工作单元通过直接在类本身中编写实体来实现.

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;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

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

我可能听起来很愚蠢,但让我知道你对此的看法.

Rya*_*ton 19

工作单元模式已在实体框架中实现.

DbContext是你的工作单元.每个IDbSet都是一个存储库.

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

  • 你有没有用其他东西替换你的数据库提供商?在15年的软件开发过程中,我从未见过有人这样做,我也无法理解能够签署此类变更的管理团队.然而,将数据库实现保留在更高级别的代码之外是一个好主意,我同意你的观点.但是,我只是远离做一个完整的工作单元模式,只是创建一个新的层,完全正如我在上面的代码中所做的那样. (13认同)
  • 我已经在一个高度分布式系统中使用完全模拟的压力测试和协议测试实现替换了数据库提供程序.使用真实数据库是不可能的,因为它比模拟数据库慢100倍. (10认同)
  • 从EF获得单独的工作单元和存储库的关键是它允许您用其他东西替换EF提供程序.例如,如果你需要模拟的只是一个`Get(int)`调用,那么在执行单元测试时假的模拟提供者更容易实现,因为更大的大小,所以模拟暴露的IDbSet对象要困难得多.界面. (5认同)
  • DbContext不是一个工作单元.它只能被视为简单应用程序中的一个工作单元.工作单元是需要在单个事务中完成的所有工作.这可能涉及多个数据库上下文,发布到异步消息总线,生成外发邮件等. (3认同)

Hon*_*how 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();
   }
}
Run Code Online (Sandbox Code Playgroud)

如果您没有从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;
   }
}
Run Code Online (Sandbox Code Playgroud)

我个人认为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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*sen 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用:

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