Pull to refresh
22
0
Дмитрий Панюшкин @gnaeus

Пользователь

Send message

Да, но за каждый новый слой абстракции надо платить. И будет ли от этого упрощение поддержки — зависит от проекта.

Больше абстракций богу абстракций! Это уже не репозиторий даже. Это как Session в Nhibernate.
Репозиторий это коллекция доменных объектов. А тут у нас все вперемешку лежит. Да еще и UoW сбоку приклепали. Не скажу, что получилось неудобно. Но это скорее про уменьшение boilerplate, чем про разделение ответственностей.
Только на практике чаще бывает наоборот. По крайней мере в .NET.
— Сначала люди начитаются туториалов, и пишут свой абстрактный репозиторий. Почему-то им кажется, что они-то спроектируют его лучше уже готовых.
— Потом начинают использовать его в других проектах внутри конторы.
— Потом оформляют в NuGet пакет.

И чем зависимость от своего пакета абстракций лучше зависимости от пакета абстракций Microsoft? Как-то NIH-синдромом попахивает. Это даже безотносительно затрат на поддержку своей реализации.

Ну, я Вам про цели, а Вы мне про средства. Тогда уж — какие преимущества мы получим, если изолирует бизнес-логику от инфраструктуры? И важны ли кто преимущества для данного конкретного проекта.

Я имею в виду когда нужен не граф связанных сущностей, а именно что dto. Например коммент + логин автора, а не коммент+автор

Ну, во-первых, не знаю как другие ОРМ, а EntityFramework предоставляет сразу несколько паттернов: DataMapper, QueryBuilder, Repository, UnitOfWork. И незачем их переизобретать.


Во-вторых не класс из ОРМ вместо репозитория, а интерфейс из ОРМ.


А в остальном согласен.

Вообще забавный пример. Там предлагают передавать в .Include() строковые названия. Прощай Type Safety. Да и репозитории там не по фичам, а по сущностями. А что если UserRepository используется вообще везде, но с вызовом разных методов?


А Репозиторий по фичам называется уже "сервис" =).

Можно и так. Как раз этот подход реализуется в LinqKit

Если нет цели абстрагироваться от EntityFramework, то такие задачи удобнее всего решать на уровне DbContext. Например, в моем велосипеде такое есть.


А если такая побочная логика слишком нетривиальна, то лучше вообще использовать CommandHandler из CQRS. Там по крайней мере можно запрятать каждый аспект (история, аудит лог и т.п.) в свой декоратор вокруг CommandHandler. А иначе все это осядет в нашем многострадальном репоизтории.

Тут я с Вами согласен. Мне не удалось поучаствовать в кроссплатформных проектах. Потому что до недавнего времени .NET и кроссплатформа были несовместимы =)

Другой вопрос, что код с зависимостью от внешних абстракций ничего не теряет в поддерживаемости и тестируемости. Он теряет в гибкости. А нужна ли Вам такая гибкость?

И при начале разработки надо ответить на вопрос, мы действительно собираемся менять операционную систему / БД / ORM?

Если у нас «коробочное решение», то ответ — Да. А если внутренний сервис, то скорее всего «Нет».
Я вообще сторонник группировки кода по фичам, а не по паттернам, которые этот код реализует. Как компромисс — можно сделать репоизтории partial, и раскидать их по каталоагм с фичами. Так можно и все запросы посмотреть по сущности, и в огромном файле не запутаться.
Значит, мне надо было поглубже копать Хабр, прежде чем свой велосипед писать =)

Alex_ME, в общем, добавил я бенчмарки в свой проект. См. обновление статьи.


Просадка на компиляцию запроса получается в 15-30 %. А не в несколько раз, как без кеширования. И все равно укладывается в одну миллисекунду.

Но это не репозиторий — это DAL-сервис.

Как я уже писал в комментарии выше, нужно различать зависимость между архитектурными слоями и зависимость от NuGet пакетов. Если бы EntityFramework был разделен на два пакета: абстракции и реализация, как сейчас Microsoft делает для многих пакетов под dotnet core, то можно было бы "собрать" слой домена из интерфейса репозитория в пакете EntityFramework.Abstractions и набора доменных сущностей в Вашей сборке. А слой DAL — собственно сам EF.


Сейчас конечно интерфейс IDbSet лежит прямо в EF, и не совсем подходит в качестве классического репозитория. Но кастомный репозиторий получится еще хуже, по крайней мере если Вы не потратите существенное время на проектирование.

А у Вас что, права на сущности распространяются, а не на бизнес-операции?
Обычно система прав живет в слое сервисов. А их можно сделать уже такими, как Вы захотите.
Ну или вообще AOP.

О как! Ну, такой подход имеет право на жизнь. Можно правда еще поизвращаться чуть-чуть:
Сделать репозиторий как partial class, и растащить UserRepository.cs по папкам, соответствующим разным фичам. Что угодно, только бы не нарушать SRP =)

IDbSet — всего лишь интерфейс. И реализовать его не сложнее чем кастомный. Единственный косяк, что лежит он в assembly EntityFramework. Ну так до Microsoft начало доходить. И теперь они выпускают по два пакета: MyPackage.dll и MyPackage.Abstractions.dll. Может и до EntityFramework-а доберутся.
А как понять, должен быть метод именно в репозитории или еще где?
Почему не прикреплять этот метод к обработчику бизнес-процесса?

Вот например есть бизнес-процесс: модератор хабов просматривает список пользователей по дате, и принимает решение — выдавать ли инвайт. Где поместить метод фильтрации пользователей?
Ну, IDbSet предоставляет CRUD и расширенную фильтрацию. Все по Фаулеру =)
А что оптимизировать Dapper-ом в GenericRepository — CRUD или специфические запросы?
Если запросы, то это уже не Repository. Это DAO, или QueryHandler из CQRS, или вообще какой-то сервис. Короче, абстракции протекают.

Information

Rating
Does not participate
Location
Калуга, Калужская обл., Россия
Date of birth
Registered
Activity