依赖注入和 Entity Framework
Dependency injection and Entity Framework
我正在使用 MVVM light 及其 Ioc 开发一个 wpf 应用程序 SimpleIoc
。
我这样实现了存储库模式:
public interface ICrud<T> where T : class
{
IEnumerable<T> GetAll();
Task<IEnumerable<T>> AsyncGetAll();
void AddNew(params T[] items);
void Delete(params T[] items);
void Update(params T[] items);
void SaveOrUpdate(params T[] items);
}
public class Crud<T> : ICrud<T> where T : class
{
public void AddNew(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.Entity.EntityState.Added;
}
context.SaveChanges();
}
}
public void Delete(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.Entity.EntityState.Deleted;
}
context.SaveChanges();
}
}
public void Update(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
context.SaveChanges ();
}
}
public void SaveOrUpdate(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
try
{
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
}
catch (Exception)
{
context.Entry(item).State = System.Data.Entity.EntityState.Added;
context.SaveChanges();
}
}
}
}
public IEnumerable<T> GetAll()
{
using (var context = new DataEntities())
{
DbSet<T> dbSet = context.Set<T>();
return dbSet.AsEnumerable().ToList();
}
}
public Task<IEnumerable<T>> AsyncGetAll()
{
return Task.Factory.StartNew(() =>
{
var context = new DataEntities();
DbSet<T> dbSet = context.Set<T>();
return dbSet.AsEnumerable();
});
}
}
在视图模型定位器中,我像这样注入依赖项:
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<IDataService, DataService>();
SimpleIoc.Default.Register<ICrud<student>, Crud<student>>();
SimpleIoc.Default.Register<ICrud<prof>, Crud<prof>>();
//Add the other EF entities dependencies
}
我的问题是,当我要执行 crud 操作时,我必须在调用之前实例化一个 EF 实体,例如:
SimpleIoc.Default.GetInstance<ICrud<student>>().AddNew();
我需要知道:
- 像上面这样的 EF 的实例化,是否违反了 依赖注入
的概念
- 如果是这样,我该如何解决这个问题?
你不应该注入实体。实体不是服务。您使用依赖注入构建的对象图应该仅由服务组成。任何包含运行时数据(实体、消息、DTO)的东西都应该使用方法调用通过构建的对象图传递。
例如在 this and this answer and this 博客 post 上查看。
在单个 class 中混合数据和行为会使测试 DI 配置变得更加困难,并且难以应用横切关注点。但除此之外,将运行时数据(例如实体)注入服务的构造函数会导致歧义,因为不清楚要将哪个实体注入构造函数。以一些 ICustomerService
为例,它依赖于其构造函数中的 Customer
实体。我们应该在此处注入哪个实体,因为我们可能有数千个。虽然这可以通过在我们创建 ICustomerService
实现的位置(我们的 Composition Root)实现选择标准来解决,但这使得 DI 配置非常复杂,使得在业务逻辑中验证配置和结果变得非常困难在不应包含任何业务逻辑的应用程序部分中。
我正在使用 MVVM light 及其 Ioc 开发一个 wpf 应用程序 SimpleIoc
。
我这样实现了存储库模式:
public interface ICrud<T> where T : class
{
IEnumerable<T> GetAll();
Task<IEnumerable<T>> AsyncGetAll();
void AddNew(params T[] items);
void Delete(params T[] items);
void Update(params T[] items);
void SaveOrUpdate(params T[] items);
}
public class Crud<T> : ICrud<T> where T : class
{
public void AddNew(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.Entity.EntityState.Added;
}
context.SaveChanges();
}
}
public void Delete(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.Entity.EntityState.Deleted;
}
context.SaveChanges();
}
}
public void Update(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
context.SaveChanges ();
}
}
public void SaveOrUpdate(params T[] items)
{
using (var context = new DataEntities())
{
foreach (T item in items)
{
try
{
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
}
catch (Exception)
{
context.Entry(item).State = System.Data.Entity.EntityState.Added;
context.SaveChanges();
}
}
}
}
public IEnumerable<T> GetAll()
{
using (var context = new DataEntities())
{
DbSet<T> dbSet = context.Set<T>();
return dbSet.AsEnumerable().ToList();
}
}
public Task<IEnumerable<T>> AsyncGetAll()
{
return Task.Factory.StartNew(() =>
{
var context = new DataEntities();
DbSet<T> dbSet = context.Set<T>();
return dbSet.AsEnumerable();
});
}
}
在视图模型定位器中,我像这样注入依赖项:
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<IDataService, DataService>();
SimpleIoc.Default.Register<ICrud<student>, Crud<student>>();
SimpleIoc.Default.Register<ICrud<prof>, Crud<prof>>();
//Add the other EF entities dependencies
}
我的问题是,当我要执行 crud 操作时,我必须在调用之前实例化一个 EF 实体,例如:
SimpleIoc.Default.GetInstance<ICrud<student>>().AddNew();
我需要知道:
- 像上面这样的 EF 的实例化,是否违反了 依赖注入 的概念
- 如果是这样,我该如何解决这个问题?
你不应该注入实体。实体不是服务。您使用依赖注入构建的对象图应该仅由服务组成。任何包含运行时数据(实体、消息、DTO)的东西都应该使用方法调用通过构建的对象图传递。
例如在 this and this answer and this 博客 post 上查看。
在单个 class 中混合数据和行为会使测试 DI 配置变得更加困难,并且难以应用横切关注点。但除此之外,将运行时数据(例如实体)注入服务的构造函数会导致歧义,因为不清楚要将哪个实体注入构造函数。以一些 ICustomerService
为例,它依赖于其构造函数中的 Customer
实体。我们应该在此处注入哪个实体,因为我们可能有数千个。虽然这可以通过在我们创建 ICustomerService
实现的位置(我们的 Composition Root)实现选择标准来解决,但这使得 DI 配置非常复杂,使得在业务逻辑中验证配置和结果变得非常困难在不应包含任何业务逻辑的应用程序部分中。