Unit of Work & Generic repozytorium with Entity Framework 5
Używam ASP.NET MVC 4 z Entity Framework 5. Mam klasy modeli i mapy encji do mapowania istniejących tabel do tych klas modeli. Wszystko to jest dobrze ustawione i działa świetnie.
Teraz chcę z tego drwić. Stworzyłem jednostkę pracy, która pobiera DataContext i używa generycznego repozytorium. Na tej podstawie zbudowałem usługi, aby móc pobierać dane z wielu repozytoriów na raz i mieć tylko jedną instancję DataContext. To również działa świetnie.Teraz do problem: chcę przetestować usługi, z danymi makiety. Kiedy tworzę instancję Unit of Work, chcę być w stanie wstawić DataContext, który jest wyśmiewany zamiast rzeczywistego DataContext.
Próbowałem stworzyć interfejs IContext i pozwolić prawdziwemu i wyśmiewanemu DataContext zaimplementować to, ale napotkałem problemy z DbSet. Próbowałem użyć IDbSet i stworzyć FakeDbSet, ale bez powodzenia. Czytałem też w Internecie, że wyśmiewanie kontekstu z IDbSet i używanie FakeDbSet jest złe podejdźcie.
Czy masz pojęcie, jaki byłby najlepszy sposób, aby to osiągnąć? To, co mam teraz, to zachowanie, które chciałbym zachować, ale naprawdę chciałbym móc wyśmiewać dane z klas modelu w DataContext.
zdaję sobie sprawę z tego, że struktura encji zawiera już jednostkę zachowania w pracy i że nie musisz dodawać dodatkowych zachowań do tego. Ale chciałem zawinąć to wewnątrz innej klasy, która śledzi wszystkie repozytoria (o nazwie UnitOfWork klasy).
Edit: napisałem dwa artykuły wyjaśniające moje rozwiązanie zarówno z LINQ jak i Entity Framework.
Http://gaui.is/how-to-mock-the-datacontext-linq/
Http://gaui.is/how-to-mock-the-datacontext-entity-framework/
Oto mój kod:
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);
}
Iunit of work.cs
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
Repozytorium.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;
}
}
}
Przykładowy serwis.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();
}
}
Przykładowy Kontroler.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();
}
2 answers
Twoja klasa ExampleService
oczekuje IUnitOfWork
, co oznacza, że potrzebujesz innego IUnitOfWork
, który jest Mockiem, a jego metoda GetRepository()
zwróci IRepository
Mock.
public InMemoryRepository<T> : IRepository<T> where T : class
{
........
}
public InMemoryUnitOfWork : IUnitOfWork
{
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
return new InMemoryRepository<TEntity>();
}
}
Potem:
public IEnumerable<Example> GetAll()
{
// Create Unit Of Work object
IUnitOfWork uow = new InMemoryUnitOfWork();
// Create Service with Unit Of Work
ExampleService service = new ExampleService(uow);
return service.getAll();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-24 07:43:48
Możesz skorzystać z poniższego linku, który jest bardzo pomocny.
Generic repozytorium wzorzec w aplikacji MVC3 z Entity Framework
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-28 01:05:15