Я изо всех сил пытаюсь выяснить идеальную реализацию Entity Framework и шаблона хранилища.Я использую Entity Framework 4.3, сначала код, и я просто не могу понять, как правильно использовать Entity Framework.
Мне нравятся вещи, которые EF приносит в таблицу, такие как отслеживаемые сущности, ленивыйзагрузка, свойства навигации и т. д. Но некоторые из них не очень подходят для шаблона репозитория, насколько я понимаю.Давайте рассмотрим несколько примеров, и, может быть, вы, ребята, можете мне помочь.
Универсальный репозиторий против неуниверсального репозитория
Мое первоначальное впечатление от универсального репозитория заключается в том, что мне это не нравится, потому чтоМне не нужна одинаковая функциональность для каждой сущности.Например, у меня есть хранилище, в котором хранятся простые переменные (пары ключ / значение) в базе данных.Мне не нужен метод Add или Delete, потому что это статические переменные.Мне нужен только метод Update и метод Get.Универсальный репозиторий не выглядит достаточно надежным и не допускает большого количества пользовательского кода на уровне данных.Я также ненавижу, когда универсальные репозитории возвращают IQueryable<T>
, потому что это дает верхним уровням возможность писать выражения непосредственно к хранилищу данных, а верхние уровни должны предполагать, что используемая технология доступа к данным должным образом реализует IQueryable, так что она запрашивает базу данныхи не тянет все в память и не запрашивает их оттуда.
Похоже, что общие репозитории, особенно те, которые возвращают IQueryable, на самом деле не придерживаются хорошего разделения интересов.Может быть, вы, ребята, можете это понять, но сейчас я использую репозитории с явно именованными именами и только возвращаю IEnumerable или IList.
Свойства навигации
Мне нравится концепция свойств навигации,но кажется, что я редко использую их при реализации шаблона хранилища.Например, у меня есть пользователь со свойством навигации под названием «Псевдонимы».Если я хочу добавить псевдоним для пользователя, было бы очень легко добавить его через свойство навигации.
myUser.Aliases.Add(new Alias { Name="cls", Value="ClearScreen" });
Но тогда где мне позвонить dbContext.SaveChanges()
?Мне передали myUser
, и я использовал свойство навигации, чтобы избежать необходимости вставлять мой IAliasRepository
в класс, в котором я учусь. Однако у меня теперь нет возможности сохранить мой новый псевдоним в базе данных, потому что мои верхние уровнине знает о Entity Framework.Теперь я все равно должен ввести свой IAliasRepository
, чтобы я мог все _aliasRepository.SaveChanges()
.Ну, теперь это похоже на полную трату.Я чувствую, что должен был просто использовать _aliasRepository.AddAlias(newAlias)
вместо этого, так как мне все равно нужно вводить хранилище.
Само-отслеживающиеся сущности
Само-отслеживающиеся сущности - это круто, но они не дают взаймыЭто хорошо подходит для приложений, где вы пытаетесь скрыть детали слоя доступа к данным от остальной части приложения.Например, если бы я писал репозитории и совершенно не знал, что они будут использовать EF, я бы определенно добавил метод Update(Entity entity)
.Однако в EF вам не нужно этого делать, потому что вы можете просто внести изменения в сущность и затем вызвать SaveChanges()
.Сущность отслеживает все, что было изменено, и сохраняет эти изменения в базе данных.
var myEntity = _entityRepository.GetEntity("some unique ID");
myEntity.SomeProperty = "new value";
_entityRepository.SaveChanges();
Это заставляет меня исключить мои методы обновления, которые я бы включил, если бы я не знал, что EF не нуждается в них.Это усложняет ре-факторинг в будущем, потому что мне, возможно, придется вернуться и добавить правильные методы обновления.Мой единственный вариант - все равно включать методы, а потом просто ничего не делать с ними при реализации моих репозиториев.
public void UpdateEntity(Entity entity)
{
// Do nothing. EF is tracking changes and they will be persisted when
// SaveChanges() is called.
}
Так что мой код будет выглядеть так, даже если он совершенно не нужен.
var myEntity = _entityRepository.GetEntity("some unique ID");
myEntity.SomeProperty = "new value";
_entityRepository.UpdateEntity(myEntity);
_entityRepository.SaveChanges();
Полагаю, наличие пустого метода не страшно, если я просто пытаюсь поддерживать правильное разделение задач для упрощения рефакторинга позже, но это все равно кажется забавным.
Сохранение DbContextсинхронно
Еще одна странная особенность этого паттерна заключается в том, что вы должны быть очень осторожны с вашим DbContext. Один и тот же экземпляр должен быть введен во все репозитории. В противном случае, если вы извлекаете сущности из одного хранилища и пытаетесь связать их с сущностями из другого хранилища, они не будут хорошо играть вместе, потому что они из разных экземпляров DbContext. Контейнеры IoC упрощают управление, но это странная проблема для разработчиков, только начинающих с EF. Здесь на самом деле не проблема, а просто еще одна странность с Entity Framework и шаблоном хранилища.
Как правильно реализовать шаблон репозитория с EF? Как вы преодолеваете эти препятствия?