我首先使用ASP.NET MVC和Entity框架代码创建一个应用程序。我正在使用来自以下链接的影响的存储库和工作单元模式。
这里我对工作单元的实现有疑问,因为工作单元是通过直接在类本身中编写实体来实现的。
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;
}
}
}
您认为实施是否足够好,因为每次添加/删除实体时我都需要更改我的工作单元类。我认为工作单位不应该依赖于实体。因为在我的基于客户反馈的应用程序中,我们将经常添加/删除实体。
我可能听起来很愚蠢,但请告诉我你对此的看法。
答案 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);
}