依赖注入和Entity Framework [英] Dependency injection and Entity Framework
问题描述
我在做MVVM使用灯带及其IOC SimpleIoc
WPF应用程序。
我实现了资源库这样的格局:
公共接口ICrud< T>其中T:类
{
IEnumerable的< T>得到所有();
任务<&IEnumerable的LT; T>> AsyncGetAll();
无效的AddNew(PARAMS T []项目);
无效删除(PARAMS T []项目);
无效更新(PARAMS T []项目);
无效SaveOrUpdate(PARAMS T []项目);
}
公共类和界面污物LT; T> :ICrud< T>其中T:类
{
公共无效的AddNew(PARAMS T []项目)
{
使用(VAR上下文=新DataEntities())
{
的foreach(在项目牛逼的项目)
{
context.Entry(项目)= .STATE System.Data.Entity.EntityState.Added;
}
context.SaveChanges();
}
}
公共无效删除(PARAMS T []项目)
{
使用(VAR上下文=新DataEntities())
{
的foreach(在项目牛逼的项目)
{
context.Entry(项目)= .STATE System.Data.Entity.EntityState.Deleted;
}
context.SaveChanges();
}
}
公共无效更新(PARAMS T []项目)
{
使用(VAR上下文=新DataEntities())
{
的foreach(在项目牛逼的项目)
{
context.Entry(项目)= .STATE System.Data.Entity.EntityState.Modified;
}
context.SaveChanges();
}
}
公共无效SaveOrUpdate(PARAMS T []项目)使用(VAR上下文=新DataEntities
{
() )
{
的foreach(在项目牛逼的项目)
{
试
{
context.Entry(项目)= .STATE System.Data.Entity的.EntityState.Modified;
context.SaveChanges();
}
赶上(例外)
{
context.Entry(项目)= .STATE System.Data.Entity.EntityState.Added;
context.SaveChanges();
}
}
}
}
公开的IEnumerable< T> GETALL()
{
使用(VAR上下文=新DataEntities())
{
DbSet< T> dbSet = context.Set< T>();
返回dbSet.AsEnumerable()了ToList();
}
}
公共任务<&IEnumerable的LT; T>> AsyncGetAll()
{
返回Task.Factory.StartNew(()=>
{
VAR背景=新DataEntities();
DbSet< ; T> dbSet = context.Set< T>();
返回dbSet.AsEnumerable();
});
}
}
在视图模型定位,我注入这样的依赖
静态ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(()=> SimpleIoc.Default );
SimpleIoc.Default.Register< IDataService,DataService的>();
SimpleIoc.Default.Register< ICrud<学生>中和界面污物LT;学员GT;>();
SimpleIoc.Default.Register< ICrud<教授>中和界面污物LT;教授>>();
//添加其他EF实体依赖性
}
我的问题是,当我倒是呼吁例如之前执行CRUD操作我有一个实例化EF实体:
SimpleIoc.Default.GetInstance< ICrud<学员GT;>()的AddNew()。
我需要知道:
- 像上面的EF的instanciation,是它违反了依赖关系注入
- 如果是的话,如何能概念我解决这个问题?
您不应该注入实体。实体不是服务。你建立使用依赖注入的对象图,应该只包括服务。任何含有(实体,消息的DTO)应通过使用方法调用内置对象图通过运行时数据。
在一个类中混合数据和行为使得它更难考你DI配置,使得它难以应用横切关注点。但除此之外,运行时数据(如实体)注入歧义服务的构造函数的结果,因为它是不清楚注入构造它的确切实体。就拿一些 ICustomerService
这取决于客户
实体在其构造。哪个实体,我们应该在这里注入,因为我们可能有成千上万。虽然这可以通过在我们创建 ICustomerService
实现(我们的作文根)的位置实施的选择标准来解决,这使得DI配置非常复杂,使得它真的很难验证在不应该包含任何业务逻辑的应用程序的一部分中的业务逻辑的配置和效果。
I'm doing a wpf application using MVVM light with its Ioc SimpleIoc
.
I implemented the repository pattern like this :
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();
});
}
}
in the viewmodel locator , I inject the dependencies like this :
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
}
My problem is when I'd to perform a crud operation I have to instanciate an EF entity before calling for example :
SimpleIoc.Default.GetInstance<ICrud<student>>().AddNew();
I need to know :
- the instanciation of an EF like above, is it a violation of the concept of Dependency Injection
- If it is the case, How can I fix this problem?
You shouldn't inject entities. Entities are not services. The object graphs that you build using dependency injection, should solely consist of services. Anything that contains runtime data (entities, messages, DTOs) should be passed through the built object graph using method calls.
Take a look for instance at this and this answer and this blog post.
Mixing data and behavior in a single class makes it much harder to test you DI configuration and makes it hard to apply cross-cutting concerns. But besides that, injecting runtime data (such as entities) into a service's constructor results in ambiguity, because it is unclear which exact entity to inject into the constructor. Take for instance some ICustomerService
that depends on a Customer
entity in its constructor. Which entity should we inject here, since we might have thousands. Although this can be solved by implementing the selection criteria in the location where we create the ICustomerService
implementation (our Composition Root), this makes the DI configuration very complex, makes it really hard to verify the configuration and results in business logic in a part of the application that should not contain any business logic.
这篇关于依赖注入和Entity Framework的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!