Здравствуйте, Spinifex, Вы писали:
S>Уже гораздо лучше, чем у @Danchik. Самое главное автору данного кода пришло осознание, что запрос GetUsersOnTheFlat может встречаться более чем в одном сервисе. И нужно куда-то его вынести, чтобы не делать copy/past.
S>Repository как раз для этого и предназначен.
S>Причем в моем представлении этот запрос гораздо более сложный может быть c джойнами на организацию, на здание, на информацию по зданию и т.п.
Ты неправильно мня понял. Я как раз против универсального GetUsersOnTheFlat. Одно дело, когда нужно получить список пользователей на этаже для того, чтобы отправить им почтовое уведомление, а другое дело, когда нужно начислить им компенсацию за не работающий лифт. Или уволить всех скопом.
Если сделать универсальный метод, возвращающий коллекцию пользователей с полным набором атрибутов, то работать он будет везде неэффективно.
С linq2db можно не бояться джоинов, поскольку он автоматически генерирует схему, включающую и описания таблиц, и связи между ними для легкой навигации parent->child и обратно.
И тогда джоин на здание или организацию будет выполняться простым обращением к свойству.
_db.User.Select(u => new { StreetName = u.Room.Building.Street.Name, OrgName = u.Organization.Name })
S>Остался вопрос относительно функций Commit(), Rollback(), BeginTransaction(). Им в репозитории совсем не место. Опять же если вы обратитесь к моему примеру у меня в методе сервиса использовалось 3 репозитория. Чей в таком случае Rollback вызывать? А Commmit. Понятно что для вашего кода это без разницы. Но дизайн кода, что должен думать программист его использующий?
S>Хорошо бы вынести эти функции в какой-то класс, который абстрагирует нас от DbNorthwind заодно. Но в случае с linq2db это сделать проблематично, т.к. там торчат наружу коллекции сущностей. Зачем-то. Нафига? Никто не знает ответа. Даже автор.
Да, единый коммит и роллбэк будут выполняться через DbNorthwind.
Торчат наружу не коллекции, а IQueriable интерфейсы к таблицам, что позволяет гибко извлекать ровно те данные, которые нужны для конкретного сервиса.
S>Поэтому в сервисах будет DbNorthwind и меньший уровень абстракции, чем мог бы быть.
Ты знаешь, для меня меньший уровень абстракции к СУБД — это большой плюс.
Для меня ORM должна быть тонким типизованным фасадом к данным, а не абстракцией.
Главное — типизация и возможность декомпозиции и реюза запросов.
А уж поверх этого я и абстракцию (какая именно мне нужна) прикручу и все прочее.
И чтобы два раза не вставать, вот пример декомпозиции, позволяющий реюзать фильтр пользователей по этажу.
IQueryable<UserModel> ApplyFilterByFlat(IQueryable<UserModel> source, int flat)
{
return source.Where(u => u.Room.Flat == flat);
}
Теперь этот предикат можно переиспользовать множество раз, комбинируя с другими условиями. И без copy-paste.
А если подключить LinqKIT, то декомпозировать и переиспользовать можно не только условия выборки, но и составные части проекции.
Я имею ввиду фичу AsExpandable (детали здесь —
http://www.albahari.com/nutshell/linqkit.aspx и
http://tomasp.net/blog/linq-expand.aspx)
Кстати, давно хочу попросить Игоря IT включить эту фичу в linq2db. С тех пор как нашел ее, использую во всех проектах.