Я пишу новое приложение на C # поверх платформы Prism 6.3 , используя известный шаблон проектирования MVVM.Я использую контейнер Unity IoC, чтобы помочь мне управлять своими зависимостями.
Я использую Entity Framework Core для взаимодействия с базой данных.Однако я не хочу тесно связывать свое приложение с Entity Framework Core, поэтому я реализовал шаблоны Repository
и UnitOfWork
, чтобы мне было проще заменить реализацию Entity Framework Core при необходимости.
Моя реализация репозитория предоставляет метод с именем Save()
, который вызывает метод SaveChanges()
EF Core.Репозитории внедряются в мой бизнес-сервис, так что мой бизнес-сервис предоставляет один метод для выполнения одной задачи.Например, если я хочу создать новый заказ, я бы вызвал метод Create(orderViewModel)
, который внутренне вызывает метод Add()
и Save()
для OrderRepository
.
Кроме того, UnitOfWork
предоставляет Save()
, BeginTransaction()
, Commit()
и Rollback()
методы, которые позволяют мне контролировать поведение транзакции.Другими словами, это даст мне возможность либо фиксировать, либо откатывать транзакцию SQL при необходимости.
Чтобы лучше объяснить мой вариант использования, вот пример того, как я мог бы добавить новый заказ в свою базу данных напрямую, используябизнес-сервис без транзакции или единицы работы.
OrdersService.Create(orderViewModel); // this will call the `Add` and the `Save()` methods on the OrderRepository;
Вот еще один пример, который демонстрирует, как я мог бы добавить новый заказ и позиции заказа в свою базу данных, используя бизнес-сервисы при использовании unit-работы для запуска транзакции и управления транзакцией.
using(var transaction = UnitOfWork.BeginTransaction())
{
try
{
var order = OrdersService.Create(orderViewModel);
OrdersService.CreateRange(order.Id, orderItemsViewModel);
transaction.Commit();
}
catch(Exception e)
{
Log.Add(e);
transaction.RollBack();
}
}
Во втором приведенном выше примере, хотя каждый из OrdersService.Save
и OrdersService.SaveRange
вызывает метод SaveChanges()
, данные которого не передаютсябазу данных, поскольку я обертываю их транзакцией.
Вопрос : что LifeTimeManager , если я должен зарегистрировать DbContext
, IUnitOfWork
и каждый из моих репозиториев с помощью?
В веб-среде я регистрировал бы все, используя PerRequestLifetimeManager
, тогда во время запроса я использую тот же DbContext
и всеОн работает нормально, и DbContext
располагается в конце http-запроса.Но не уверен, как зарегистрировать все в приложении WPF, где я все еще могу использовать транзакцию, чтобы контролировать все, позволяя хранилищу вызывать SaveChanges()
При необходимости здесь моя реализация EntityRepository
public class EntityRepository<TEntity, TKeyType> : IRepository<TEntity, TKeyType>
where TEntity : class
where TKeyType : struct
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public TEntity Get(TKeyType id)
{
return DbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
public bool Any(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Any(predicate);
}
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.SingleOrDefault(predicate);
}
public virtual TEntity Add(TEntity entity)
{
var record = Context.Add(entity);
record.State = EntityState.Added;
return entity;
}
public virtual IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
{
Context.AddRange(entities);
return entities;
}
public void Remove(TEntity entity)
{
Context.Remove(entity).State = EntityState.Deleted;
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
Context.RemoveRange(entities);
}
public void Update(TEntity entity)
{
DbSet.Attach(entity);
var record = Context.Entry(entity);
record.State = EntityState.Modified;
}
public IQueryable<TEntity> Query()
{
return DbSet;
}
public void Save()
{
Context.SaveChanges();
}
}
А вот моя единица выполнения работы
public sealed class UnitOfWork : IUnitOfWork
{
private bool IsDisposed = false;
private readonly DbContext Context;
public IOrderRepository Orders { get; private set; }
public IOrderItemRepository OrderItems { get; private set; }
public UnitOfWork(DbContext context)
{
Context = context;
Orders = new OrderRepository(context);
OrderItems = new OrderItemRepository(context);
}
public int Save()
{
Context.SaveChanges();
return 0;
}
public void Dispose()
{
Dispose(true);
}
public IDatabaseTransaction BeginTransaction()
{
return new EntityDatabaseTransaction(Context);
}
private void Dispose(bool disposing)
{
if (IsDisposed)
{
return;
}
if (disposing)
{
Context.Dispose();
}
IsDisposed = true;
}
}