Я тоже смотрел это видео перед написанием статьи =) На первый взгляд, там все правильно и красиво. Единственный вопрос — а зачем?
место хранения часто используемых запросов к сущности
А вот тут уже суровая реальность: Вы будете выносить запросы в репозиторий по мере рефакторинга. А Ваш коллега просто напихает от балды. Со временем все равно класс распухнет. Потому что его ответственность "часто используемые запросы" слишком размыта. Группировать запросы надо. Но по бизнес-кейсам, а не по сущностями.
IEnumerable<Post> Filter(PostCriteria criteria);
class PostCriteria
{
public int? AuthorId { get; set; }
public DateTime? Date { get; set; }
public string Tag { get; set; }
// и т.п.
}
Только вот замокать репозиторий с достаточно богатым API — та еще задачка. Лучше уж In-Memory Context. А вот IQueryable замокать элементарно — new List<T>().
Это Вы про extension-методы? Хороший вопрос на самом деле. Надо проверять.
Но, чисто умозрительно, кэширование должно работать. Магия не встраивается внутрь EF. Она работает как декоратор вокруг LINQ IQueryable. И тот Expression, который содержится во внутреннем IQueryable из EntityFramework, уже не содержит никакой магии. Ну и компиляция SQL происходит из нормального ExpressionTree.
В принципе, когда мы добавляем в цепочку вызовов еще один LINQ-метод:
query.Where(...).Select(...).OrderBy(...)
мы точно так же модифицируем IQueryable.Expression.
Ну это как-то ортогонально созданию кастомного репозитория.
А вот насчет Repository и UnitOfWork — либо через год они превратятся в неподдерживаемое нечто (времени на рефакторинг не хватило). Либо со временем окажется, что Вы пишете на собственном фреймворке поверх EF (времени хватило).
А еще, такие репозитории — это пустая абстракиця. В них нет ни бизнес-логики, ни инфраструктурной логики. Это как адаптер. Только он используется не для интеграции двух разных модулей. А для интеграции EF и кода, который еще даже не написан.
Тут я пожалуй соглашусь. Мне самому комфортнее с extension-методами. Особенно, если дополнить их возможностью вызова из ExpressionTree, как описано в конце статьи.
Спецификации — это не способ облегчить жизнь разработчику, а скорее способ оформить все "по феншую" (DDD, TDD, переиспользование и т.п.).
И еще иногда (очень редко) возникает потребность динамически комбинировать условия с выборки помощью OR. Для AND все просто — добавляем в цепочку запроса несколько .Where()
А для OR или спецификация, или PredicateBuilder из LinqKit
Зато теперь можно тыкнуть их носом в эту статью =)
У меня за последние три года несколько раз случались холивары на эту тему с товарищами по команде.
Причем в разных конторах. Вот, решил оформить свои мысли в статью.
Я тоже смотрел это видео перед написанием статьи =) На первый взгляд, там все правильно и красиво. Единственный вопрос — а зачем?
А вот тут уже суровая реальность: Вы будете выносить запросы в репозиторий по мере рефакторинга. А Ваш коллега просто напихает от балды. Со временем все равно класс распухнет. Потому что его ответственность "часто используемые запросы" слишком размыта. Группировать запросы надо. Но по бизнес-кейсам, а не по сущностями.
А вот от догмы, что все запросы к MyEntity должны лежать в MyEntityRepository нужно отступить.
Тогда уж лучше сразу
Но я про другое. Для extension-методов:
И их можно использовать в подзапросах в в отличие от..
Только вот замокать репозиторий с достаточно богатым API — та еще задачка. Лучше уж In-Memory Context. А вот IQueryable замокать элементарно —
new List<T>()
.Это Вы про extension-методы? Хороший вопрос на самом деле. Надо проверять.
Но, чисто умозрительно, кэширование должно работать. Магия не встраивается внутрь EF. Она работает как декоратор вокруг LINQ IQueryable. И тот Expression, который содержится во внутреннем IQueryable из EntityFramework, уже не содержит никакой магии. Ну и компиляция SQL происходит из нормального ExpressionTree.
В принципе, когда мы добавляем в цепочку вызовов еще один LINQ-метод:
мы точно так же модифицируем
IQueryable.Expression
.Ну это как-то ортогонально созданию кастомного репозитория.
А вот насчет Repository и UnitOfWork — либо через год они превратятся в неподдерживаемое нечто (времени на рефакторинг не хватило). Либо со временем окажется, что Вы пишете на собственном фреймворке поверх EF (времени хватило).
А еще, такие репозитории — это пустая абстракиця. В них нет ни бизнес-логики, ни инфраструктурной логики. Это как адаптер. Только он используется не для интеграции двух разных модулей. А для интеграции EF и кода, который еще даже не написан.
Тут я пожалуй соглашусь. Мне самому комфортнее с extension-методами. Особенно, если дополнить их возможностью вызова из ExpressionTree, как описано в конце статьи.
Спецификации — это не способ облегчить жизнь разработчику, а скорее способ оформить все "по феншую" (DDD, TDD, переиспользование и т.п.).
И еще иногда (очень редко) возникает потребность динамически комбинировать условия с выборки помощью OR. Для AND все просто — добавляем в цепочку запроса несколько .Where()
А для OR или спецификация, или PredicateBuilder из LinqKit
У меня за последние три года несколько раз случались холивары на эту тему с товарищами по команде.
Причем в разных конторах. Вот, решил оформить свои мысли в статью.