[英]using UnitOfWork and Repository Pattern with Entity Framework
我将在我的数据访问层中使用存储库和UnitOfwork来执行此操作,查看一个联系人aggregateroot
public interface IAggregateRoot
{
}
这是我的Generic存储库接口:
public interface IRepository<T>
{
IEnumerable<T> 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; }
}
这是我继承自IRepository的IContactRepository,也可能是自己的方法
public interface IContactRepository : IRepository<Contact>
{
}
现在我已经完成了IUitOfWork和UnitOfwork
public interface IUnitOfWork
{
IRepository<Contact> ContactRepository { get; }
}
public class UnitOfWork : IUnitOfWork
{
private readonly StatosContext _statosContext = new StatosContext();
private IRepository<Contact> _contactUsRepository;
public IRepository<Contact> ContactRepository
{
get { return _contactUsRepository ?? (_contactUsRepository = new Repository<Contact>(_statosContext)); }
}
}
关于我的存储库
public class Repository<T> : IRepository<T> 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和泛型方法)因为我想获得一些特定查询的ContactRepository方法,所以有人帮忙吗?
它不是您问题的直接答案,但它可以简化一些事情并减少重复。
当您使用例如EntityFramework Power Tools对Code First进行逆向工程时(或者通常仅使用Code First),您最终会使用DbContext
类作为UoW和存储库,例如:
public partial class YourDbContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
现在,如果你想让事情变得可测试,那么有一个简单的方法:引入一个非常精简的界面:
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.
}
然后使用分部类的第二部分创建另一个文件:
public partial class YourDbContext : IDbContext
{
public IDbSet<T> EntitySet<T>() where T : class
{
return Set<T>();
}
}
当当! 现在您可以使用YourDbContext
注入IDbContext
:
//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();
现在,如果您想控制上下文的处理,那么您必须编写自己的( 喘气 ) IDbContextFactory
(通用与否,根据您的需要)并注入该工厂。
现在不需要编写自己的Find
, Add
或Update
方法, DbContext
将适当地处理它,更容易引入显式事务,并且一切都很好地隐藏在接口后面( IDbContext
, IDbSet
)。
顺便说一句, IDbContextFactory
将等同于NHibernate的ISessionFactory
和IDbContext
- ISession
。 我希望EF也能开箱即用。
我同意Doctor,DbContext已经是一个UnitOfWork,并且在它之上添加另一个UoW抽象通常是多余的,除非你认为你很可能在未来转换数据库技术。
但是,我不同意将DbSet视为存储库,因为这会将查询与使用它们的方法紧密结合。 如果您需要更改查询,则必须在使用它的任何地方执行此操作。
我更喜欢使用独立的存储库(或服务接口,它们提供类似的功能),或者使用更多的CQRS系统进行命令/查询分离,即使用查询对象。
在UnitOfWork类中,您需要实现DBContext或ObjectContext。
无论系统如何,UnitOfWork都会隔离所有事务。 EF仅用于数据库连接。 即使您的系统仅使用数据库,最好还是保留一个单独的UnitOfWork类以用于将来的扩展。
在工作单元Commit()中,您可以调用内部实现的DBContext.SaveChanges()。
单元工作中声明的所有存储库都可以访问此DBcontext。 所以在DBcontext中添加或删除存储库,unitOfwork会提交它。
当您拥有跨越不同存储的场景时,例如:云Blob,表存储等。您可以在UnitofWork中实现它们,就像您实现EF上下文一样。 一些存储库可以访问表存储和一些EF上下文。
提示:实现ObjectContext而不是DBContext为缓存方案提供了优势。 您可以在扩展框架方面有更多选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.