且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在实体框架中使用UnitOfWork和存储库模式

更新时间:2022-11-04 21:20:26

这不是您问题的直接答案,但可能会简化一些工作,并且减少重复。

It's not a direct answer to your question, but it might simplify things a little bit and reduce duplication.

使用例如EntityFramework Power Tools可以对Code First(或通常只使用Code First)进行逆向工程,最后得到 DbContext 类,该类用作一个UoW和一个存储库,例如:

When you use e.g. EntityFramework Power Tools to reverse-engineer Code First (or just use Code First in general), you end up with the DbContext class that serves as a UoW and repository in one, e.g.:

public partial class YourDbContext : DbContext
{
    public DbSet<Contact> Contacts {get; set;}
}

现在,如果您希望事物可以测试,那么很容易方式:引入一个非常薄的接口:

Now, if you want things to be testable, there's an easy way: introduce a very thin interface:

public interface IDbContext
{
    IDbSet<T> EntitySet<T>() where T : class;
    int SaveChanges();
    //you can reveal more methods from the original DbContext, like `GetValidationErrors` method or whatever you really need.
}

然后用分部类的第二部分制作另一个文件:

then make another file with second part of the partial class:

public partial class YourDbContext : IDbContext
{
     public IDbSet<T> EntitySet<T>() where T : class
     {
         return Set<T>();
     }
}

Ta-da!现在,您可以注入 IDbContext YourDbContext 进行备份:

Ta-da! Now you can inject IDbContext with YourDbContext backing it up:

//context is an injected IDbContext:
var contact = context.EntitySet<Contact>().Single(x => x.Id == 2);    
contact.Name = "Updated name";
context.EntitySet<Contact>().Add(new Contact { Name = "Brand new" });
context.SaveChanges();

现在,如果您想控制上下文的处理,则必须编写您自己的( gasp IDbContextFactory (是否通用,取决于您的需要)并注入该工厂。

Now if you want to have control over the disposal of the context, then you'd have to write your own (gasp) IDbContextFactory (generic or not, depending what you need) and inject that factory instead.

无需编写自己的查找添加更新方法, DbContext 将适当地处理该问题,更容易引入显式事务,并且所有内容都很好地隐藏在接口后面( IDbContext IDbSet )。

No need to write your own Find, Add or Update methods now, DbContext will handle that appropriately, it's easier to introduce explicit transactions and everything is nicely hidden behind interfaces (IDbContext, IDbSet).

顺便说一下, IDbContextFactory 相当于NHibernate的 ISessionFactory IDbContext - ISession 。我希望EF也能做到这一点。

By the way, the IDbContextFactory would be an equivalent to NHibernate's ISessionFactory and IDbContext - ISession. I wish EF had this out of the box, too.