使用UnitOfWork和存储库模式与entity framework

我将在我的数据访问层中使用存储库和UnitOfwork来执行此操作,查看一个联系人aggregateroot

public interface IAggregateRoot { } 

这是我的Generic存储库接口:

  public interface IRepository { IEnumerable GetAll(); T FindBy(params Object[] keyValues); void Add(T entity); void Update(T entity); void Delete(T entity); } 

和我在模型中的POCO Contact类

  public class Contact :IAggregateRoot { public Guid Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string Title { get; set; } public string Body { get; set; } public DateTime CreationTime { get; set; } } 

这是我inheritance自IRepository的IContactRepository,也可能是自己的方法

  public interface IContactRepository : IRepository { } 

现在我已经完成了IUitOfWork和UnitOfwork

 public interface IUnitOfWork { IRepository ContactRepository { get; } } public class UnitOfWork : IUnitOfWork { private readonly StatosContext _statosContext = new StatosContext(); private IRepository _contactUsRepository; public IRepository ContactRepository { get { return _contactUsRepository ?? (_contactUsRepository = new Repository(_statosContext)); } } } 

关于我的存储库

 public class Repository : IRepository where T : class, IAggregateRoot { //implementing methods } 

我可以通过Service中的UnitOfwork访问存储库来执行所有CRUD操作,例如:

 _unitOfWork.ContactRepository.Add(contact); _unitOfWork.SaveChanges(); 

但我想这样做

_

 ContactRepository.Add(contact); _unitOfWork.SaveChanges(); 

(通过_unitOfWork.ContactRepository通过_ContactRepository No获取CRUD和generics方法)因为我想获得一些特定查询的ContactRepository方法,所以有人帮忙吗?

这不是你问题的直接答案,但它可以简化一些事情并减少重复。

当您使用例如EntityFramework Power Tools对Code First进行反向工程(或者只是使用Code First)时,最终会使用DbContext类作为UoW和存储库,例如:

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

现在,如果你想让事情变得可测试,那就有一个简单的方法:引入一个非常精简的界面:

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

然后使用部分类的第二部分创建另一个文件:

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

当当! 现在您可以使用YourDbContext注入IDbContext

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

现在,如果您想控制上下文的处理,那么您必须编写自己的( 喘气IDbContextFactory (通用与否,根据您的需要)并注入该工厂。

现在不需要编写自己的FindAddUpdate方法, DbContext将适当地处理它,更容易引入显式事务,并且一切都很好地隐藏在接口( IDbContextIDbSet )之后。

顺便说一句, IDbContextFactory将等同于NHibernate的ISessionFactoryIDbContextISession 。 我希望EF也能开箱即用。

我同意Doctor,DbContext已经是一个UnitOfWork,并且在它之上添加另一个UoW抽象通常是多余的,除非你认为你很可能在未来转换数据库技术。

但是,我不同意将DbSet视为存储库,因为这会将查询与使用它们的方法紧密结合。 如果您需要更改查询,则必须在使用它的任何地方执行此操作。

我更喜欢使用独立的存储库(或服务接口,它们提供类似的function)或使用更多的CQRS系统进行命令/查询分离,这是一个使用查询对象。

在UnitOfWork类中,您需要实现DBContext或ObjectContext。

无论系统如何,UnitOfWork都会隔离所有事务。 EF仅用于数据库连接。 即使您的系统仅使用数据库,最好还是保留一个单独的UnitOfWork类以供将来扩展。

在工作单元Commit()中,您可以调用内部实现的DBContext.SaveChanges()。

单元工作中声明的所有存储库都可以访问此DBcontext。 因此,从DBcontext添加或删除存储库,unitOfwork会提交它。

当您拥有跨越不同存储的场景时,例如:Cloud Blob,表存储等。您可以在UnitofWork中实现它们,就像您实现EF上下文一样。 一些存储库可以访问表存储和一些EF上下文。

提示:实现ObjectContext而不是DBContext为缓存方案提供了优势。 您可以在扩展框架方面有更多选择。