Entity Framework, свойства навигации и шаблон репозитория

Я изо всех сил пытаюсь найти идеальную реализацию Entity Framework и шаблон репозитория. Я использую код Entity Framework 4.3 в первую очередь, и я просто не могу понять правильное использование инфраструктуры сущностей.

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

Универсальный репозиторий в сравнении с неуниверсальным репозиторием

Мое первоначальное впечатление от универсального репозитория заключается в том, что он мне не нравится, потому что мне не нужны одни и те же функции для каждой сущности. Например, у меня есть репозиторий, в котором хранятся простые переменные (пары ключ/значение) в базе данных. Мне не нужен метод Add или Delete, потому что это статические переменные. Мне нужен только метод Update и метод Get. Общий репозиторий просто не кажется очень надежным и не позволяет использовать много пользовательского кода на уровне данных.Я также ненавижу, когда общие репозитории возвращают IQueryable, потому что это дает верхним уровням возможность писать выражения непосредственно для хранилища данных, и верхние уровни должны предполагать, что используемая технология доступа к данным правильно реализует 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? Как вы преодолеваете эти препятствия?

31
задан Chev 6 March 2012 в 20:02
поделиться