Информация об изменениях

Сообщение Re[8]: Альтернативы EF Core от 17.08.2017 17:24

Изменено 17.08.2017 17:24 Nikita Lyapin

Re[8]: Альтернативы EF Core
Здравствуйте, sergeya, Вы писали:

S>Привет!


SAS>>Spinifex не поленился и привел пусть и схематичный, но все же пример. Можете показать как при вашем способе это выглядит на практике?


S>Не увидел в примере специфики, завязанной на возможности EF. Его можно повторить на linq2db строка в строку.

S>Заменить unitOfWork на dataConnection (можно даже назвние прежнее оставить) и код будет совпадать один в один.
S>Только под капотом у репозиториев будет не EF а linq2db.

S>Примерный код репозитория:


S>
S>class OrganizationRepository 
S>{
S>    DbNorthwind _db;
S>    public OrganizationRepository(DbNorthwind dataConnection)
S>    {
S>        _db = dataConnection;
S>    }

S>    public void Commit()
S>    {
S>        _db.Commit();
S>    }

S>    public void Rollback() { ... }

S>    public void BeginTransaction() { ... }

S>    public List<User> GetUsersOnTheFlat(int flat) 
S>    {
S>        return _db.User
S>            .Where(u => u.Room.Flat == flat)
S>            .ToList();
S>    }
S>}
S>


S>>... всегда могу из контекста достать данные без обращения в базу ...


S>Не всегда, а только если их туда предварительно положить.

S>И если репозиторий рассчитывает на данные из unitOfWork, то это означает появление неявного контракта со всеми вытекающими неприятностями.
S>Можно неосторожно забить на сложность получения данных из БД в надежде, что данные уже лежат в контексте. И получить сюрприз, когда сервис будет вызван в другом сценарии.
S>По мне так надежнее передавать данные между сервисами в явном виде. А если нужен долговременный кэш, то реализовать его в виде специального сервиса.

S>Подход с кэшированием в unitOfWork хорошо работает на учебных примерах с простыми плоскими моделями.

S>В реальной жизни появляются сложные развесистые документы, и внезапно оказывается, что разным сервисам нужны разные проекции одного и того же документа.
S>Сервису рассылки — email, а сервису начисления зарплаты — должность пользователя.
S>И данные, закешированные одним сервисом, не подойдут для другого.

S>Поэтому считаю, что в unitOfWork вместо метода Get(id), возвращающего материализованную проекцию, должен торчать IQueryable интерфейс к БД.


S>Кстати, вызов GetUsersOnTheFlat только для того, чтобы вытащить из базы email пользователей тоже выглядит оверхеадом.

S>У меня бы метод рассылки уведомлений требовал бы на входе только id пользователя, и сам вытаскивал бы по этому id из БД только данные, необходимые для выполнения рассылки.

Уже гораздо лучше, чем у @Danchik. Самое главное автору данного кода пришло осознание, что запрос GetUsersOnTheFlat может встречаться более чем в одном сервисе. И нужно куда-то его вынести, чтобы не делать copy/past.
Repository как раз для этого и предназначен.
Причем в моем представлении этот запрос гораздо более сложный может быть c джойнами на организацию, на здание, на информацию по зданию и т.п.
Остался вопрос относительно функций Commit(), Rollback(), BeginTransaction(). Им в репозитории совсем не место. Опять же если вы обратитесь к моему примеру у меня в методе сервиса использовалось 3 репозитория. Чей в таком случае Rollback вызывать? А Commmit. Понятно что для вашего кода это без разницы. Но дизайн кода, что должен думать программист его использующий?
Хорошо бы вынести эти функции в какой-то класс, который абстрагирует нас от DbNorthwind заодно. Но в случае с linq2db это сделать проблематично, т.к. там торчат наружу коллекции сущностей. Зачем-то. Нафига? Никто не знает ответа. Даже автор.
Поэтому в сервисах будет DbNorthwind и меньший уровень абстракции, чем мог бы быть.

P.S. Обратите внимание как @Danchik был вынужден упростить код моей функции. У него простая вставка в User. Это как бы намекает какой из подходов используется в реальных боевых проектах, а какой в учебных. Потому как в реальности дело обстоит так (текущих примеров достаточно чтобы понять это):
Re[8]: Альтернативы EF Core
Уже гораздо лучше, чем у @Danchik. Самое главное автору данного кода пришло осознание, что запрос GetUsersOnTheFlat может встречаться более чем в одном сервисе. И нужно куда-то его вынести, чтобы не делать copy/past.
Repository как раз для этого и предназначен.
Причем в моем представлении этот запрос гораздо более сложный может быть c джойнами на организацию, на здание, на информацию по зданию и т.п.
Остался вопрос относительно функций Commit(), Rollback(), BeginTransaction(). Им в репозитории совсем не место. Опять же если вы обратитесь к моему примеру у меня в методе сервиса использовалось 3 репозитория. Чей в таком случае Rollback вызывать? А Commmit. Понятно что для вашего кода это без разницы. Но дизайн кода, что должен думать программист его использующий?
Хорошо бы вынести эти функции в какой-то класс, который абстрагирует нас от DbNorthwind заодно. Но в случае с linq2db это сделать проблематично, т.к. там торчат наружу коллекции сущностей. Зачем-то. Нафига? Никто не знает ответа. Даже автор.
Поэтому в сервисах будет DbNorthwind и меньший уровень абстракции, чем мог бы быть.

P.S. Обратите внимание как @Danchik был вынужден упростить код моей функции. У него простая вставка в User. Это как бы намекает какой из подходов используется в реальных боевых проектах, а какой в учебных. Потому как в реальности дело обстоит так (текущих примеров достаточно чтобы понять это):