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 aCustomer
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 theICustomerService
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.