Использование шаблона UnitOfWork и репозитория с платформой Entity Framework

Я собираюсь использовать репозиторий и UnitOfwork на моем уровне доступа к данным, чтобы сделать это, взгляните на один контакт aggregateroot

public interface IAggregateRoot
 {
 }

это мой общий интерфейс репозитория:

public interface IRepository<t>
 {
 IEnumerable<t> GetAll();
 T FindBy(params Object[] keyValues);
 void Add(T entity);
 void Update(T entity);
 void Delete(T entity);
 }
</t></t>

и мой класс контактов POCO в модели

public class Contact :IAggregateRoot
 {
 public Guid Id { get; set; }
 public string Name { get; set; }
 public string Email { get; set; }
 public string Title { get; set; }
 public string Body { get; set; }
 public DateTime CreationTime { get; set; }
 }

и этот мой IContactRepository, который наследует от IRepository, а также может иметь собственный метод

public interface IContactRepository : IRepository<contact>
 {
 }
</contact>

Теперь я сделал в IUitOfWork и UnitOfwork, как этот

public interface IUnitOfWork 
 {
 IRepository<contact> ContactRepository { get; }
 }
public class UnitOfWork : IUnitOfWork
 {
 private readonly StatosContext _statosContext = new StatosContext();
 private IRepository<contact> _contactUsRepository;
 public IRepository<contact> ContactRepository
 {
 get { return _contactUsRepository ?? (_contactUsRepository = new Repository<contact>(_statosContext)); }
 }
}
</contact></contact></contact></contact>

также о моем репозитории

public class Repository<t> : IRepository<t> where T : class, IAggregateRoot
 {
 //implementing methods 
 }
</t></t>

Я могу выполнить всю операцию CRUD с доступом к репозиториям с помощью UnitOfwork в службе, например:

_unitOfWork.ContactRepository.Add(contact);
 _unitOfWork.SaveChanges();

но я хочу сделать это

_

ContactRepository.Add(contact);
 _unitOfWork.SaveChanges();

(получить CRUD и общий метод через _ContactRepository Нет _unitOfWork.ContactRepository) Поскольку я хочу получить метод ContactRepository для некоторых конкретных запросов, кто-нибудь поможет пожалуйста??

3 ответа

Это не прямой ответ на ваш вопрос, но он может немного упростить ситуацию и уменьшить дублирование.

Когда вы используете, например, EntityFramework Power Tools для обратного преобразования кода Сначала (или просто используйте Code First вообще), вы получаете класс DbContext, который служит в качестве UoW и репозитория в одном, например:

public partial class YourDbContext : DbContext
{
 public DbSet<contact> Contacts {get; set;}
}
</contact>

Теперь, если вы хотите, чтобы все проверялось, есть простой способ: ввести очень тонкий интерфейс:

public interface IDbContext
{
 IDbSet<t> EntitySet<t>() where T : class;
 int SaveChanges();
 //you can reveal more methods from the original DbContext, like `GetValidationErrors` method or whatever you really need.
}
</t></t>

затем создайте другой файл со второй частью частичного класса:

public partial class YourDbContext : IDbContext
{
 public IDbSet<t> EntitySet<t>() where T : class
 {
 return Set<t>();
 }
}
</t></t></t>

Та-да! Теперь вы можете вставить IDbContext с помощью YourDbContext резервной копии:

//context is an injected IDbContext:
var contact = context.EntitySet<contact>().Single(x => x.Id == 2); 
contact.Name = "Updated name";
context.EntitySet<contact>().Add(new Contact { Name = "Brand new" });
context.SaveChanges();
</contact></contact>

Теперь, если вы хотите получить контроль над удалением контекста, вам придется написать свой собственный (gasp) IDbContextFactory (общий или нет, в зависимости от того, что вам нужно) и вместо этого ввести factory.

Не нужно теперь писать собственные методы Find, Add или Update, DbContext будет обрабатывать это соответственно, проще вводить явные транзакции, и все прекрасно скрывается за интерфейсами (IDbContext, IDbSet).

Кстати, IDbContextFactory будет эквивалентен NHibernate ISessionFactory и IDbContext - ISession. Я бы хотел, чтобы EF тоже был в курсе.


Я согласен с Доктором, DbContext уже является UnitOfWork, и добавление еще одной абстракции UoW поверх нее, как правило, избыточно, если вы не считаете, что в будущем вы можете переключать технологии баз данных.

Я не согласен, однако, рассматривать DbSet как репозитории, так как это тесно связывает ваши запросы с методами, которые их используют. Если вам нужно изменить запрос, вы должны сделать это везде, где вы его используете.

Я предпочитаю использовать автономный репозиторий (или служебный интерфейс, они выполняют аналогичные функции) или использовать больше системы CQRS для Command/Query Seperation, объектов запросов использования.


Внутри класса UnitOfWork вам необходимо реализовать DBContext или ObjectContext.

UnitOfWork разделяет все транзакции независимо от системы. EF предназначен только для соединения с БД. Даже если ваша система использует только БД, лучше сохранить отдельный класс UnitOfWork для будущих расширений.

И внутри единицы работы Commit() вы можете вызвать внутренне реализованный DBContext.SaveChanges().

Этот DBcontext будет доступен для всех репозиториев, объявленных внутри unitofwork. Таким образом, репозитории добавляют или удаляют из DBcontext, и unitOfwork совершает это.

Когда у вас есть сценарии, охватывающие разные хранилища, например: Cloud Blob, хранилище таблиц и т.д. Вы можете реализовать их внутри UnitofWork так же, как вы реализовали контекст EF. И некоторые репозитории могут получить доступ к хранилищу таблиц и некоторому контексту EF.

Совет. Реализация ObjectContext вместо DBContext дает вам преимущество в сценариях кеширования. И у вас есть больше возможностей для расширения вашей рамки.

licensed under cc by-sa 3.0 with attribution.