Sto utilizzando ASP.NET MVC 4 con Entity Framework 5. Ho classi di modelli e mappe di entità per associare tabelle esistenti a tali classi di modelli. Tutto questo è impostato bene e funziona alla grande.Unità di lavoro e repository generico con Entity Framework 5
Ora voglio prendere in giro questo. Ho creato Unit Of Work che prende DataContext e utilizza un repository generico. Da quel momento ho creato servizi per poter ottenere dati da più repository contemporaneamente e ho solo bisogno di avere un'istanza di DataContext. Anche questo funziona alla grande.
Ora al problema: Voglio testare i servizi, con dati falsi. Quando creo l'istanza Unit Of Work, voglio essere in grado di inserire un DataContext che viene deriso al posto del DataContext reale.
Ho cercato di creare un'interfaccia IContext e lasciare che il DataContext reale e deriso lo implementasse, ma ha incontrato problemi con DbSet. Ho provato a usare IDbSet e creare un FakeDbSet ma senza successo. Ho anche letto su internet che prendersi gioco del contesto con IDbSet e usare FakeDbSet è un approccio sbagliato.
Avete qualche idea di quale sarebbe il modo migliore per raggiungere questo obiettivo? Quello che ho ora è il comportamento che vorrei mantenere, ma mi piacerebbe davvero essere in grado di prendere in giro i dati dalle classi Model nel DataContext.
Sono consapevole del fatto che Entity Framework è già dotato del comportamento Unità di lavoro e che non è necessario aggiungere ulteriore comportamento in più. Ma volevo racchiuderlo all'interno di un'altra classe che tenesse traccia di tutti i repository (chiamata classe UnitOfWork).
Modifica: Ho scritto due articoli che spiegano la mia soluzione con LINQ e Entity Framework.
http://gaui.is/how-to-mock-the-datacontext-linq/
http://gaui.is/how-to-mock-the-datacontext-entity-framework/
Ecco il mio codice:
IRepository.cs
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(long Id);
IEnumerable<T> All();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
IUnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
Repository.cs
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDbContext _context;
private readonly IDbSet<T> _dbset;
public Repository(IDbContext context)
{
_context = context;
_dbset = context.Set<T>();
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
var entry = _context.Entry(entity);
entry.State = System.Data.EntityState.Deleted;
}
public virtual void Update(T entity)
{
var entry = _context.Entry(entity);
_dbset.Attach(entity);
entry.State = System.Data.EntityState.Modified;
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dbset.Where(predicate);
}
}
UnitOfWork.cs
public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
private readonly IDbContext _ctx;
private Dictionary<Type, object> _repositories;
private bool _disposed;
public UnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
_disposed = false;
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
if (_repositories.Keys.Contains(typeof(TEntity)))
return _repositories[typeof(TEntity)] as IRepository<TEntity>;
var repository = new Repository<TEntity>(_ctx);
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void Save()
{
_ctx.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
_ctx.Dispose();
}
this._disposed = true;
}
}
}
ExampleService.cs
public class ExampleService
{
private IRepository<Example> m_repo;
public ExampleService(IUnitOfWork uow)
{
m_repo = uow.GetRepository<Example>();
}
public void Add(Example Example)
{
m_repo.Add(Example);
}
public IEnumerable<Example> getAll()
{
return m_repo.All();
}
}
EsempioController.cs
public IEnumerable<Example> GetAll()
{
// Create Unit Of Work object
IUnitOfWork uow = new UnitOfWork<AppDataContext>();
// Create Service with Unit Of Work attached to the DataContext
ExampleService service = new ExampleService(uow);
return service.getAll();
}
Inoltre sto avendo lo stesso problema come lei ha ricordato. Tuttavia, puoi pubblicare il tuo codice per IDbContext e la classe concreta che implementa IDbContext? Questo mi aiuterà molto. Grazie in anticipo. – NoobDeveloper
@Nexus [http://gaui.is/how-to-mock-the-datacontext-entity-framework/](http://gaui.is/how-to-mock-the-datacontext-entity-framework/) – Gaui
@Gaui Non sarebbe meglio creare l'istanza 'UnitOfWork' all'interno della classe' ExampleService' al posto del controller? In questo modo il tuo controller non ha bisogno di sapere di cosa 'DbContext' ha bisogno, lo lascia al servizio. – GFoley83