Работа с ORM
От: Аноним  
Дата: 26.07.11 04:31
Оценка:
Решили в проекте использовать ORM (NHibernate) и возник вопрос как реализовать доступ к объектам.
Подскажите какое из решений лучше:

1) Реализовать все как св-ва IUnitOfWork

public interface IUnitOfWork
{
   ....
   IQueryable<User> Users{get;}
}


использование:

public UserRepository:IUserRepository
{
......
    public IQueryable<User> Items
    {
       return _iUnitOfWork.Users;
    }
}

И здесь возникает вопрос насколько правильно использовать в методе сервиса свойства UOW в обход репозитариев:


class UserService
{
somemethod()
{
   var t=from u in  IUnitOfWork.Users
         ...join .. IUnitOfWork.Pages
        where...
        .... select u
}
}



2)Реализовать непосредственно в репозитории:
public UserRepository:IUserRepository
{
......
    public IQueryable<User> Items
    {
       return _session.Query<User>();
    }
}


3) Подвариант 2-го использовать дженериковский репозиторий
Re: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 05:47
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:

А>Решили в проекте использовать ORM (NHibernate) и возник вопрос как реализовать доступ к объектам.

А>Подскажите какое из решений лучше:

Сессия и есть UnitOfWork, ничего не надо больше ничего абстрагировать. Максимум можно свой потомок сделать, с со свойствами IQueryable<Entity> и то, лучше обойтись extension methods.

Репозитарии только увеличивают размер кода, не решая никакой архитектурной проблемы, являясь рудиментом рукописных ORM, призваных, в свое время избавить код бизнес логики от конструирования SQL. Вдобавок ко всему, репозитарии подталкивают к использованию навигационного доступа к БД, что резко увеличивает нагрузку на базу и превращает приложение в тормозное УГ.

Берите сессию и используйте ее в хвост и в гриву прямо в логике. Можно абстрагировать только время ее жизни в какой-либо легковесный IoC контейнер.
Re: Работа с ORM
От: Aviator  
Дата: 26.07.11 06:44
Оценка:
Здравствуйте, Аноним, Вы писали:

Разработчики NHibernate уже реализовали unit of work и назвали его ISession.
Re[2]: Работа с ORM
От: Аноним  
Дата: 26.07.11 07:05
Оценка:
Здравствуйте, Aviator, Вы писали:

A>Здравствуйте, Аноним, Вы писали:


A>Разработчики NHibernate уже реализовали unit of work и назвали его ISession.


Да, я это понимаю, но хочется иметь некую абстракцию в коде:


using (IUnitOfWork uow = UnitOfWork.CreateUow())
{
   uow.BeginTransaction();
   .......
   uow.CommitTransaction();
}
Re: Работа с ORM
От: Gengzu  
Дата: 26.07.11 07:10
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Решили в проекте использовать ORM (NHibernate) и возник вопрос как реализовать доступ к объектам.

А>Подскажите какое из решений лучше:

А>3) Подвариант 2-го использовать дженериковский репозиторий


3й вариант предпочтительней, ибо вносит большую прозрачность в код. к тому же при необходимости может будет заменить ORM на другой, переписав лишь репозиторий. либо вообще переход на NoSQL. Другое дело если ничего такого не предвидится никогда.

выносить наружу IQueriable плохо тем, что любой разработчик сможет дописать что угодно в запрос, а это приведёт в свою очередь как к дублированию кода, так и к кривым SQL запросам.
Re[3]: Работа с ORM
От: Aviator  
Дата: 26.07.11 07:17
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Aviator, Вы писали:


A>>Здравствуйте, Аноним, Вы писали:


A>>Разработчики NHibernate уже реализовали unit of work и назвали его ISession.


А>Да, я это понимаю, но хочется иметь некую абстракцию в коде:



А>
А>using (IUnitOfWork uow = UnitOfWork.CreateUow())
А>{
А>   uow.BeginTransaction();
А>   .......
А>   uow.CommitTransaction();
А>}
А>


И чем это противоречит использованию сессии в репозитариях? Имейте хоть десять абстракций, главное что бы они шарили одну сессию.
Re[2]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 07:20
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>3й вариант предпочтительней, ибо вносит большую прозрачность в код. к тому же при необходимости может будет заменить ORM на другой, переписав лишь репозиторий. либо вообще переход на NoSQL. Другое дело если ничего такого не предвидится никогда.


Это фантастика. Просто так взять и поменять ORM может получиться только в очень простых приложениях. А поддерживать абстракцию и бороться с ней придется весь цикл жизни приложения.

G>выносить наружу IQueriable плохо тем, что любой разработчик сможет дописать что угодно в запрос, а это приведёт в свою очередь как к дублированию кода, так и к кривым SQL запросам.


А не выносить — приведет к навигационному доступу и куче однострочников которые используются в одном месте.
Re[2]: Работа с ORM
От: Aviator  
Дата: 26.07.11 07:22
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Решили в проекте использовать ORM (NHibernate) и возник вопрос как реализовать доступ к объектам.

А>>Подскажите какое из решений лучше:

G>3й вариант предпочтительней, ибо вносит большую прозрачность в код. к тому же при необходимости может будет заменить ORM на другой, переписав лишь репозиторий. либо вообще переход на NoSQL. Другое дело если ничего такого не предвидится никогда.

Это из области фантастики, прозрачно сменить ОРМ получится только в случае очень простых запросов.

G>выносить наружу IQueriable плохо тем, что любой разработчик сможет дописать что угодно в запрос, а это приведёт в свою очередь как к дублированию кода, так и к кривым SQL запросам.

Да, это почти равноценно использованию sql запросов в коде.
Re[3]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 07:24
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Да, я это понимаю, но хочется иметь некую абстракцию в коде:


А>
А>using (IUnitOfWork uow = UnitOfWork.CreateUow())
А>{
А>   uow.BeginTransaction();
А>   .......
А>   uow.CommitTransaction();
А>}
А>


Что вам даст эта абстракция? На какой ORM вы сможете поменять NHibernate? Какие детали NHibernate она скроет?
Re[3]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 07:25
Оценка:
Z>Это фантастика. Просто так взять и поменять ORM может получиться только в очень простых приложениях. А поддерживать абстракцию и бороться с ней придется весь цикл жизни приложения.

Увы, но однажды приходилось менять ORM. И был случай перехода на NoSQL.

Z>А не выносить — приведет к навигационному доступу и куче однострочников которые используются в одном месте.


что есть навигационный доступ?
читайте о Specification pattern.
Re[4]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 07:31
Оценка:
Здравствуйте, Gengzu, Вы писали:


Z>>Это фантастика. Просто так взять и поменять ORM может получиться только в очень простых приложениях. А поддерживать абстракцию и бороться с ней придется весь цикл жизни приложения.


G>Увы, но однажды приходилось менять ORM. И был случай перехода на NoSQL.


С этого места подробнее. Сколько было сущностей, как абстрагированы и сколько всего пришлось переделать за пределами абстракций.

Z>>А не выносить — приведет к навигационному доступу и куче однострочников которые используются в одном месте.


G>что есть навигационный доступ?


foreach (var orderLine in order.Lines)
  foreach (var good in orderLine.Goods)
  {
    good.Manufacturer.Score++;
  }


G>читайте о Specification pattern.


Он отлично реализован в .net через ExpressionTree. Именно его я и советую применять выставляя наружу IQueryable.
Re[4]: Работа с ORM
От: Aviator  
Дата: 26.07.11 07:34
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, Аноним, Вы писали:


А>>Да, я это понимаю, но хочется иметь некую абстракцию в коде:


А>>
А>>using (IUnitOfWork uow = UnitOfWork.CreateUow())
А>>{
А>>   uow.BeginTransaction();
А>>   .......
А>>   uow.CommitTransaction();
А>>}
А>>


Z>Что вам даст эта абстракция? На какой ORM вы сможете поменять NHibernate? Какие детали NHibernate она скроет?

Да пусть играется с абстракциями это сейчас модно , главное что бы репозитарии использовали хибер а не непонятные абстракции.
Re[5]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 08:00
Оценка:
Z>С этого места подробнее. Сколько было сущностей, как абстрагированы и сколько всего пришлось переделать за пределами абстракций.

С десяток сущностей. Много отношений много-ко-многим. Изначально использовался EF 4.0, как маппер. После EF 4.1 CodeFirst, в итоге перешли на NHibernate, так как гибкости EF в маппингах сильно не хватало.

G>>что есть навигационный доступ?


Z>
Z>foreach (var orderLine in order.Lines)
Z>  foreach (var good in orderLine.Goods)
Z>  {
Z>    good.Manufacturer.Score++;
Z>  }
Z>


не понимаю к чему это.
изменение Score у вложенной сущности? как бы это выглядело в вашем случае?

Z>Он отлично реализован в .net через ExpressionTree. Именно его я и советую применять выставляя наружу IQueryable.


всё что необходимо скрыть, нужно скрывать. в данном случае IQueryable остаётся и никому не мешает в силу лени создания экстеншин метода, написать сразу запрос по месту.

другое дело, если ваше приложение получит доп. уровень абстракции, и данные будут выгребаться через веб-сервисы. в случаи нормального абстрагирования, нужно будет переписать лишь репозитории, и IQueriable там увы не подойдёт.

но всё сильно от задачь зависит. в HomePage такие абстракции лишние.
Re[6]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 08:16
Оценка:
Здравствуйте, Gengzu, Вы писали:

Z>>С этого места подробнее. Сколько было сущностей, как абстрагированы и сколько всего пришлось переделать за пределами абстракций.


G>С десяток сущностей. Много отношений много-ко-многим. Изначально использовался EF 4.0, как маппер. После EF 4.1 CodeFirst, в итоге перешли на NHibernate, так как гибкости EF в маппингах сильно не хватало.


Я так и не услышал ответа на весь вопрос. Впрочем дам совет, хоть он и не будет воспринят сейчас: не надо напирать на хитрые маппинги, чем они прозрачнее, тем проще разработчику работать с базой. Этот факт все равно не скроешь, хоть 50 абстракций наверни сверху.

G>не понимаю к чему это.

G>изменение Score у вложенной сущности? как бы это выглядело в вашем случае?

Очень и очень вложенной, обычная N+1 проблема навигационного доступа. В гибернейте, в моем случае, это выглядело бы как запрос к нужным сущностям, апдейт и сохранение. Именно таким запросам мешают различные репозитарии вкупе с запретом на IQueryable. В bltoolkit вообще, прямой апдейт в БД.

Z>>Он отлично реализован в .net через ExpressionTree. Именно его я и советую применять выставляя наружу IQueryable.


G>всё что необходимо скрыть, нужно скрывать. в данном случае IQueryable остаётся и никому не мешает в силу лени создания экстеншин метода, написать сразу запрос по месту.


Я рад, что развеял заблуждение:

выносить наружу IQueriable плохо тем, что любой разработчик сможет дописать что угодно в запрос, а это приведёт в свою очередь как к дублированию кода, так и к кривым SQL запросам.


G>другое дело, если ваше приложение получит доп. уровень абстракции, и данные будут выгребаться через веб-сервисы. в случаи нормального абстрагирования, нужно будет переписать лишь репозитории, и IQueriable там увы не подойдёт.


Когда получит тогда и надо вводить его. Сто процентов что, введенный сейчас он не ляжет на неожиданно возникшие вебсервисы органично, будут нюансы.

G>но всё сильно от задачь зависит. в HomePage такие абстракции лишние.


Ну мы то сейчас не о HomePage, впрочем в одном моем домашнем проекте сущностей уже больше 10. И логика меняется постоянно. И все абстракции, кроме используемой платформы — выкинуты. Полет нормальный.

P.S. Я сам несколько лет назад любил NH именно за хитрые маппинги. Но тогда не было строготипизированного доступа к БД, который дает LINQ.
Re[7]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 08:32
Оценка:
Z>Я так и не услышал ответа на весь вопрос. Впрочем дам совет, хоть он и не будет воспринят сейчас: не надо напирать на хитрые маппинги, чем они прозрачнее, тем проще разработчику работать с базой. Этот факт все равно не скроешь, хоть 50 абстракций наверни сверху.

Чего конкретно не хватает в ответе?
За пределами сущностей пришлось переделать очень не много, и то скорее потому, что RepositoryХзЧто привелись к нормальному GenericRepository с использованием Specification, что дало возможность выгребать везде одинаково необходимое кол-во необходимых сущностей, включая вложенные, при необходимости.

Ну и не ясно что значит "не надо напирать на хитрые маппинги". Они могут быть продиктованы бизнесс-требованиями, имеющейся базой данных, которая уже есть такая какая есть и её нужно замапить.

Z>Очень и очень вложенной, обычная N+1 проблема навигационного доступа. В гибернейте, в моем случае, это выглядело бы как запрос к нужным сущностям, апдейт и сохранение. Именно таким запросам мешают различные репозитарии вкупе с запретом на IQueryable. В bltoolkit вообще, прямой апдейт в БД.


глупости. сделайте эту сущность Aggregation Root, и получите к ним доступ через репозиторий. не вижу проблем.

Z>Я рад, что развеял заблуждение:


нет, не развеяли. выносить IQueriable очень плохая практика, нарушающая инкапсуляцию. Expression можно юзать, но свобода остаётся. а чем больше свободы — там проще написать неправильный код.

Z>Когда получит тогда и надо вводить его. Сто процентов что, введенный сейчас он не ляжет на неожиданно возникшие вебсервисы органично, будут нюансы.


Паттерн Repository по сути является не чем иным, как реализацией массива в памяти с разными заморочками. Если он таким и будет оставатся, то в совокупности с UnitOfWork, привязывание его к веб-сервисам пройдёт прозрачно.
Re[5]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 08:35
Оценка:
A>Да пусть играется с абстракциями это сейчас модно , главное что бы репозитарии использовали хибер а не непонятные абстракции.

Так а репозитории что дают? Кроме возможности поменять ORM? Их же надо писать. И потом проталкивать каждый метод дергания БД в них. Вместо того, чтобы писать Users.Where(u => u.Sex == Sex.Male), приходится писать


IUserRepository.cs:
IList<User> GetUsersBySex(Sex sex);

UserRepository.cs:
IList<User> GetUsersBySex(Sex sex) 
{
   return session.Linq<User>().Where(u => u.Sex == sex).ToList();
}

текущий код:
UserRepository.GetUsersBySex(Sex.Male)


Пишем и радуемся абстракциям. У нас такой клевый метод. Его могут все использовать. Потом приходит аналитик и говорит: там оказывается не мужчины нужны, а мальчики, моложе 14 лет. И что будет делать программер? Его метод уже все используют. Добавить в него фильтр по возрасту — означает поломать чей-то код. Вобщем он либо пишет новый метод GetUsersBySexYongerThat (в лучшем случае), либо (в худшем) в коде делает фильтр по возрасту у результата GetUsersBySex, в результате мы имеем в памяти (и сессии) в несколько раз больше объектов чем нужно. А гибернейт очень нервно относится к количеству объектов в сессии, там производительность то ли O(N) то ли O(N^2). И это падение не происходит за один день. Оно копится милисикундами.

Вобщем я не выдумываю небылицы, это собственный опыт.
Re[6]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 08:46
Оценка:
Z>Пишем и радуемся абстракциям. У нас такой клевый метод. Его могут все использовать. Потом приходит аналитик и говорит: там оказывается не мужчины нужны, а мальчики, моложе 14 лет. И что будет делать программер? Его метод уже все используют. Добавить в него фильтр по возрасту — означает поломать чей-то код.

та же проблема возникает с прямыми запросами. когда нужно выбирать не только мальчиков, вы будете править 100+ мест где написали этот ваш запрос.
Re[8]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 08:49
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>Чего конкретно не хватает в ответе?

G>За пределами сущностей пришлось переделать очень не много, и то скорее потому, что RepositoryХзЧто привелись к нормальному GenericRepository с использованием Specification, что дало возможность выгребать везде одинаково необходимое кол-во необходимых сущностей, включая вложенные, при необходимости.

О! GenericRepository это же чудесно. Вместо того, чтобы писать кучу бесполезного кода, мы его засунем в шаблон и волшебно получим свою порцию бесползеного кода для каждой сущности. Вобщем Specification таки добро оказалось, это радует.

G>глупости. сделайте эту сущность Aggregation Root, и получите к ним доступ через репозиторий. не вижу проблем.


То есть, как только я не могу сделать адекватный запрос, я должен вынести Aggregation Root, дать доступ к репозитарию. Ничего, что программисту дают оптимистичные сроки и он не захочет создавать новые репозитарии на простенький запрос? На него же еще и тесты писать придется.

G>нет, не развеяли. выносить IQueriable очень плохая практика, нарушающая инкапсуляцию. Expression можно юзать, но свобода остаётся. а чем больше свободы — там проще написать неправильный код.


Инкапсуляцию чего? Я привел кучу примеров, когда к неправильному коду приводит именно несвобода написать правильный затратив адекватные усилия. Жду примеров, когда писать неправильный код диктует свобода.

G>Паттерн Repository по сути является не чем иным, как реализацией массива в памяти с разными заморочками. Если он таким и будет оставатся, то в совокупности с UnitOfWork, привязывание его к веб-сервисам пройдёт прозрачно.


Блажен кто верует. Как только данные неожиданно придется отдавать наружу, возникнет сразу столько проблем, что есть репозитарии или нет архитектор уже не заметит. Даже если до этого считал, что репозитарии ему чем-то помогут в данном случае.
Re[7]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 08:51
Оценка:
Здравствуйте, Gengzu, Вы писали:

Z>>Пишем и радуемся абстракциям. У нас такой клевый метод. Его могут все использовать. Потом приходит аналитик и говорит: там оказывается не мужчины нужны, а мальчики, моложе 14 лет. И что будет делать программер? Его метод уже все используют. Добавить в него фильтр по возрасту — означает поломать чей-то код.


G>та же проблема возникает с прямыми запросами. когда нужно выбирать не только мальчиков, вы будете править 100+ мест где написали этот ваш запрос.


Черта с два, ситуаций, когда мальчики должны быть в 100+ юзкейсах аналитики промаргивают значительно реже. Если это один юзкейс, то и запрос будет один.
Re[9]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 09:17
Оценка:
Z>О! GenericRepository это же чудесно. Вместо того, чтобы писать кучу бесполезного кода, мы его засунем в шаблон и волшебно получим свою порцию бесползеного кода для каждой сущности. Вобщем Specification таки добро оказалось, это радует.

о каком бесполезном коде идёт речь? куда мы что засунем?

Z>То есть, как только я не могу сделать адекватный запрос, я должен вынести Aggregation Root, дать доступ к репозитарию. Ничего, что программисту дают оптимистичные сроки и он не захочет создавать новые репозитарии на простенький запрос? На него же еще и тесты писать придется.


опять глупость. один GenericRepository обслуживает ВСЕ сущности в проекте. один класс с десятком методов по 1-3 строки каждый, пишется не так долго, правда?)

Z>Инкапсуляцию чего? Я привел кучу примеров, когда к неправильному коду приводит именно несвобода написать правильный затратив адекватные усилия. Жду примеров, когда писать неправильный код диктует свобода.


я не вижу ваших примеров. увы.
но в вашем случае, я уже писал. и чуть выше пример приводили. ну нет у вас метода на получение всех мальчиков старше 18 лет, ну и напишет паренёк Users.Where(u => u.Age > 18) по месту в методе, а метод этот вернёт этот же результат в виде IQueriable дальше, где еще кто-то припишет запросик. какой-то.
получим и дублирование кода, и чёрти какие SQL запросы.
в случае использования спецификаций, достаточно будет изменить её одну, что бы получить необходимый результат во всех нужных местах.
плюс вся эта логика обычно обёрнута сервисным уровнем.


Z>Блажен кто верует. Как только данные неожиданно придется отдавать наружу, возникнет сразу столько проблем, что есть репозитарии или нет архитектор уже не заметит. Даже если до этого считал, что репозитарии ему чем-то помогут в данном случае.


где проблемы? какие проблемы? репозиторий помогает унифицировать CRUD операции и абстрагироваться от хранилища данных. этого достаточно.
Re[8]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 09:19
Оценка:
Z>Черта с два, ситуаций, когда мальчики должны быть в 100+ юзкейсах аналитики промаргивают значительно реже. Если это один юзкейс, то и запрос будет один.

у нас есть админка. в ней 10 страниц. на всех страницах должны отображаться только активные пользователи.
в случае прямых запросов, которые с таким подходом скорее всего будут писаться по месту, изменять придётся в этих 10 местах.
Re[10]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 09:43
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>о каком бесполезном коде идёт речь? куда мы что засунем?

G>опять глупость. один GenericRepository обслуживает ВСЕ сущности в проекте. один класс с десятком методов по 1-3 строки каждый, пишется не так долго, правда?)
G>где проблемы? какие проблемы? репозиторий помогает унифицировать CRUD операции и абстрагироваться от хранилища данных. этого достаточно.

Так зачем абстрагировать CRUD, если для этого уже написан и отлажен ORM, он имеет отличный API для этого. Для чего абстрагировать CRUD через ORM?

Z>>Инкапсуляцию чего? Я привел кучу примеров, когда к неправильному коду приводит именно несвобода написать правильный затратив адекватные усилия. Жду примеров, когда писать неправильный код диктует свобода.


G>я не вижу ваших примеров. увы.

G>но в вашем случае, я уже писал. и чуть выше пример приводили. ну нет у вас метода на получение всех мальчиков старше 18 лет, ну и напишет паренёк Users.Where(u => u.Age > 18) по месту в методе, а метод этот вернёт этот же
результат в виде IQueriable дальше, где еще кто-то припишет запросик. какой-то.
G>получим и дублирование кода, и чёрти какие SQL запросы.

Я не вижу никакого дублирования. Нет никакой разницы в дублировании, напишет он вызов YongerThat или u.Age >. Если ограничение на 18 лет имеет свое бизнес название — нет никакой проблемы вынести его в именованый предикат. Репозитарий для этого совершенно не нужен. Черти какие запросы мы гарантированно получим максимально абстрагировав их от прикладного программиста. Он все равно выберет данные которые ему нужны, только ни о какой эффективности речи не будет, если у него в руках нет прямого способа сделать нужный запрос.

G>в случае использования спецификаций, достаточно будет изменить её одну, что бы получить необходимый результат во всех нужных местах.

G>плюс вся эта логика обычно обёрнута сервисным уровнем.
G>у нас есть админка. в ней 10 страниц. на всех страницах должны отображаться только активные пользователи.
G>в случае прямых запросов, которые с таким подходом скорее всего будут писаться по месту, изменять придётся в этих 10 местах.

Ты пойми, я тебя не уговариваю дублировать код. Я не понимаю, почему для избавления от дублирования нужны репозитарии. Не требуется никаких абстракций от CRUD, останется ровно тот же CRUD. Не требуется никаких абстракций, чтобы устранить дублирование кода запросов кроме экстеншенов к IQueryable, а абстрагироваться от него себе дороже. Что еще ты пытаешься абстрагировать за фасадом репозитария?
Re[9]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 09:45
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>у нас есть админка. в ней 10 страниц. на всех страницах должны отображаться только активные пользователи.

G>в случае прямых запросов, которые с таким подходом скорее всего будут писаться по месту, изменять придётся в этих 10 местах.

У вас на каждой странице есть код который отображает этих пользователей? И кто тут говорил о вреде дублирования?
Re[10]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 09:47
Оценка:
Z>У вас на каждой странице есть код который отображает этих пользователей? И кто тут говорил о вреде дублирования?

по тем или иным критериям.

где-то мы просто список возвращаем, где-то отфильтрованных по каком-то критерию.
разные ситуации. но это вполне нормальный юзКейс.
Re[11]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 09:57
Оценка:
Здравствуйте, Gengzu, Вы писали:

Z>>У вас на каждой странице есть код который отображает этих пользователей? И кто тут говорил о вреде дублирования?


G>по тем или иным критериям.


G>где-то мы просто список возвращаем, где-то отфильтрованных по каком-то критерию.

G>разные ситуации. но это вполне нормальный юзКейс.

ок, поступило требование везде отображать активных пользователей, было 10 страниц с:
session.Users.Where(this page condition);

стало:
session.Users.Active().Where(this page condition);


Давай свою версию с репозитарием. Не забудь свое условие, что до этого у всех страниц были разные фильтры, либо они вообще отсутствовали.
Re[11]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 09:58
Оценка:
Z>Так зачем абстрагировать CRUD, если для этого уже написан и отлажен ORM, он имеет отличный API для этого. Для чего абстрагировать CRUD через ORM?

для абстрагирования от ORM.
другое дело, необходимо ли это.
зависит от задач.
для некоторых вполне позволительно прямое обращение к ORM, а где-то увы.
вариаций для чего, хватает.

Z>>>Инкапсуляцию чего? Я привел кучу примеров, когда к неправильному коду приводит именно несвобода написать правильный затратив адекватные усилия. Жду примеров, когда писать неправильный код диктует свобода.


Z>Я не вижу никакого дублирования. Нет никакой разницы в дублировании, напишет он вызов YongerThat или u.Age >. Если ограничение на 18 лет имеет свое бизнес название — нет никакой проблемы вынести его в именованый предикат.


собственно это и есть спецификации. другое дело, что предоставление IQueriable не накладывает ограничений на его применение, и пользователь волен поступать как ему заблагорассудится. в случае репозитария у него будет только один контролируемый выход.

Z>Репозитарий для этого совершенно не нужен. Черти какие запросы мы гарантированно получим максимально абстрагировав их от прикладного программиста. Он все равно выберет данные которые ему нужны, только ни о какой эффективности речи не будет, если у него в руках нет прямого способа сделать нужный запрос.


обычно ерунду люди творят тогда, когда могут. в моём случаи — они не могут.
конечно никто не защищён от того что он в любом месте заюзает чистый ADO.NET. но это крайности.
запросы с использованием репозитория вполне нормальные.
возможно у вас проблема в построении самой архитектуры, определении Aggregation Root'ов, либо непонимании предназначения паттерна Repository.
он, кстати, для простых веб-сайтов не очень подходит. да.

Z>Ты пойми, я тебя не уговариваю дублировать код. Я не понимаю, почему для избавления от дублирования нужны репозитарии. Не требуется никаких абстракций от CRUD, останется ровно тот же CRUD. Не требуется никаких абстракций, чтобы устранить дублирование кода запросов кроме экстеншенов к IQueryable, а абстрагироваться от него себе дороже. Что еще ты пытаешься абстрагировать за фасадом репозитария?


репозиторий абстрагирует нас от хранилища данных, и от ORM.
репозиторий не для избавления от дублирования, но в данном случае, и использованием IQueriable, он предохраняет от него. как минимум.
еще раз повторюсь, выставление и протаскивание IQueriable через все слои приводит к очень плохим sql запросам, плохо тестируемому коду, дублированию кода и размазаной логики. это же очевидно.
Re[12]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 10:07
Оценка:
Z>ок, поступило требование везде отображать активных пользователей, было 10 страниц с:
Z>
Z>session.Users.Where(this page condition);
Z>

Z>стало:
Z>
Z>session.Users.Active().Where(this page condition);
Z>


Z>Давай свою версию с репозитарием. Не забудь свое условие, что до этого у всех страниц были разные фильтры, либо они вообще отсутствовали.


repository.Find<User>(new ActiveUserSpecification())
было везде, как минимум. при необходимости мы меняем спецификацию, либо унаследованную от этой с добавлением условия, либо через new ActiveUserSpecification().And(new AgeMoreThen(18))

это даст гарантию того, что, когда поменяется условие отбора активных пользователей, например с простой проверки флага IsActive, на проверку еще по дате, мы везде получим ожидаемый результат.

и в вашем случае в общем-то тоже. но в вашем же случае, пользователь может очередной метод Active и не написать. зачем? ведь у него есть IQueriable, и можно сразу влепить запрос. в моём, увы, не сможет.

проблем тут заключается именно в возможности обхода.
Re[12]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 10:12
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>репозиторий абстрагирует нас от хранилища данных, и от ORM.


Как тут хорошо процитировал Sinix:

They abstracted the Inversion of Control Container

(c)

вот еще полезная ссылка: http://www.joelonsoftware.com/articles/fog0000000018.html

G>репозиторий не для избавления от дублирования, но в данном случае, и использованием IQueriable, он предохраняет от него. как минимум.


Черт побери, IQueryable придумали, чтобы люди строили запросы с его помощью. А не для того, чтобы абстрагироваться от него за лесом тривиальных методов.

G>еще раз повторюсь, выставление и протаскивание IQueriable через все слои приводит к очень плохим sql запросам, плохо тестируемому коду, дублированию кода и размазаной логики. это же очевидно.


Совсем не очевидно. Настолько не очевидно, что я требую доказательств. Как и доказательство того, что запрос надо строить максимально далеко от слоя БД и протаскивать его через все слои попутно добавляя в них чего-то там. Я знаю, что так может получиться, если самостоятельно нарисовать кучу этих самых слоев, только вот зачем это делать?
Re[13]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 10:21
Оценка:
Z>Черт побери, IQueryable придумали, чтобы люди строили запросы с его помощью. А не для того, чтобы абстрагироваться от него за лесом тривиальных методов.

IQueriable очень хороший интерфейс, но увы, часто его использование приводит к непредсказуемым последствиям. и я не против его использования как такового, но я против протаскивания его через все слои приложения.

Z>Совсем не очевидно. Настолько не очевидно, что я требую доказательств. Как и доказательство того, что запрос надо строить максимально далеко от слоя БД и протаскивать его через все слои попутно добавляя в них чего-то там. Я знаю, что так может получиться, если самостоятельно нарисовать кучу этих самых слоев, только вот зачем это делать?


что именно не очевидно?

кто сказал что запрос нужно строить максимально далеко? наоборот. репозиторий лежит как можно ближе к нему. между ними только ORM.

имея IQueriable, человек начнёт писать запросы прямо в контроллере, например, при использовании ASP.NET MVC. и ведь начнёт. что приведёт опять же к размазанной дублируемой логики, плюс проблемы с тестированием.
Re[13]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 10:32
Оценка:
Здравствуйте, Gengzu, Вы писали:

Z>>Давай свою версию с репозитарием. Не забудь свое условие, что до этого у всех страниц были разные фильтры, либо они вообще отсутствовали.


G>repository.Find<User>(new ActiveUserSpecification())

G>было везде, как минимум. при необходимости мы меняем спецификацию, либо унаследованную от этой с добавлением условия, либо через new ActiveUserSpecification().And(new AgeMoreThen(18))

Вобщем для каждого поля сущности вы придумали написать руками тонну классов: AgeMoreThen, AgeLessThen, AgeEqualTo, AgeBetween, AgeIsNull какие еще? Только почему-то не учтен момент, что вместо ActiveUserSpecification кто-то напишет ActiveIsTrue.

G>и в вашем случае в общем-то тоже. но в вашем же случае, пользователь может очередной метод Active и не написать. зачем? ведь у него есть IQueriable, и можно сразу влепить запрос. в моём, увы, не сможет.


Ага, а результат тот же! Кроме того, что у меня программист может вместо введения/использования метода Active() написать Where(u => u.IsActive). Черт побери, вероятность этого, помноженная на вероятность того, что это создаст проблемы никак не сравнится с вредом проекту который утонул в множестве Specifications и разработке специального фреймворка для них. И уж совершенно точно комбинируя Specifications построить мало мальски сложный запрос нереально.

Если вдруг мне придется избавиться от флага IsActive, я совершенно точно буду вынужден просмотреть все использования этого флага. И это придется делать в любом случае. Особенно если они спрятаны во что-то типа (кстати, как вы различаете спецификации для разных сущностей?)
Re[14]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 10:43
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>IQueriable очень хороший интерфейс, но увы, часто его использование приводит к непредсказуемым последствиям. и я не против его использования как такового, но я против протаскивания его через все слои приложения.


Еще раз. Зачем его протаскивать через все слои?

Z>>Совсем не очевидно. Настолько не очевидно, что я требую доказательств. Как и доказательство того, что запрос надо строить максимально далеко от слоя БД и протаскивать его через все слои попутно добавляя в них чего-то там. Я знаю, что так может получиться, если самостоятельно нарисовать кучу этих самых слоев, только вот зачем это делать?


G>что именно не очевидно?


Я русским языком написал что. Повторять не буду.

G>кто сказал что запрос нужно строить максимально далеко? наоборот. репозиторий лежит как можно ближе к нему. между ними только ORM.


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

G>имея IQueriable, человек начнёт писать запросы прямо в контроллере, например, при использовании ASP.NET MVC. и ведь начнёт. что приведёт опять же к размазанной дублируемой логики, плюс проблемы с тестированием.


А если и начнет? Где-то это вполне допустимо. На то они и контроллеры. Там где недопустимо — достаточно не инжектить в контроллер сессию, а инжектить сервисы, делающие нужные операции с БД. Это совсем не репозитарии, они абстрагируют бизнес логику, а не CRUD. Тестировать же операции с БД будет сложно в любом случае, в контроллере они или еще где.
Re[15]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.07.11 11:10
Оценка: +1
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, Gengzu, Вы писали:


G>>IQueriable очень хороший интерфейс, но увы, часто его использование приводит к непредсказуемым последствиям. и я не против его использования как такового, но я против протаскивания его через все слои приложения.


Z>Еще раз. Зачем его протаскивать через все слои?


Затем что запрос эффективнее строить там где наиболее полно известна информация об этом запросе. А известна она на уровне UI.
Например:
1)Пользователь нажал на страницу 2 в списке каких-то объектов
2)В UI есть информация какой список объектов нужен и что вызвана страница 2
3)Код PL выполняет получение списка объектов из сервиса BL (IQueryable) и выполняет разбивку на страницы .Skip(...).Take(...), накладывает проекции, материализует для передачи UI.
3)Сервис BL получает от Repository IQueryable, фильтрует все Hidden объекты и накладывает предикаты видимости в зависимости от роли пользователя.
4)Repository является тонкой оберткой на ORM, чтобы в тестах его можно было заменить на что-то полегче.

Если не протаскивать IQueryable, то придется "протаскивать" передачу параметров из UI в нижние слои. Причем под каждый набор параметров понадобится свой метод, что приведет у увеличению количества методов, копипасте и другим плохим вещам.
Re[16]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 11:38
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Затем что запрос эффективнее строить там где наиболее полно известна информация об этом запросе. А известна она на уровне UI.

G>Например:
G>1)Пользователь нажал на страницу 2 в списке каких-то объектов
G>2)В UI есть информация какой список объектов нужен и что вызвана страница 2
G>3)Код PL выполняет получение списка объектов из сервиса BL (IQueryable) и выполняет разбивку на страницы .Skip(...).Take(...), накладывает проекции, материализует для передачи UI.
G>3)Сервис BL получает от Repository IQueryable, фильтрует все Hidden объекты и накладывает предикаты видимости в зависимости от роли пользователя.
G>4)Repository является тонкой оберткой на ORM, чтобы в тестах его можно было заменить на что-то полегче.

G>Если не протаскивать IQueryable, то придется "протаскивать" передачу параметров из UI в нижние слои. Причем под каждый набор параметров понадобится свой метод, что приведет у увеличению количества методов, копипасте и другим плохим вещам.


Протаскивается только предикат и протаскивается в одну сторону. Против этого я ничего не имею. Все протаскивание выглядит так PL->BL->DAL.

Обертку ORM для облегчения тестирования, конечно, сделать можно, только зачем называть ее Repository и делать для каждой сущности? Тем более мок фреймворки могут делать такие обертки на лету. Я же тестирую такие вещи прямо на базе с тестовыми данными, не идеально, но работает. Заодно позволяет заметить некоторые проблемы производительности.
Re[17]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 11:40
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Протаскивается только предикат и протаскивается в одну сторону. Против этого я ничего не имею. Все протаскивание выглядит так PL->BL->DAL.


Причем DAL это уже ORM, так что остается передача от одного слоя к другому. Правда с обработкой в слое безопасности.
Re[14]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 11:49
Оценка:
Z>Ага, а результат тот же!

нет. результат не тот.
у меня все спецификации покрыты тестами. так же есть тесты на репозиторий. все сервисные методы так же покрыты тестами, так как известно какие типы и данные ходят, какие спецификации используются. контроллеры почти не содержат кода и так же легко поддаются тестированию.

а у тебя, скорее всего, каша.
Re[17]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 11:53
Оценка: :)
Z>зачем называть ее Repository и

если она реализует этот паттерн, то так её и следует называть. но никто не заставляет его юзать.

Z>делать для каждой сущности?


что за глупости?
Re[15]: Работа с ORM
От: Ziaw Россия  
Дата: 26.07.11 12:02
Оценка: +1 :)
Здравствуйте, Gengzu, Вы писали:

Z>>Ага, а результат тот же!


G>нет. результат не тот.

G>у меня все спецификации покрыты тестами. так же есть тесты на репозиторий. все сервисные методы так же покрыты тестами, так как известно какие типы и данные ходят, какие спецификации используются. контроллеры почти не содержат кода и так же легко поддаются тестированию.

Машушвать! Продемонстрируй ка тест на AgeLessThan и расскажи, что не покрыто тестами у меня? Ты сам то понял, что сейчас наконец расписался в том, что создал всю эту бодягу только для того, чтобы ее же радостно покрыть тестами? Готов спорить, что у тебя для тестов этой штуки придумана еще очень неслабая инфраструктура для тестирования.

У меня, между прочим, 100% покрытие всего этого и оно абсолютно не требует усилий, так как покрыть 0 строк кода стоит ровно ничего.

G>а у тебя, скорее всего, каша.


Тут спорить не буду. Тебе конечно, виднее.
Re[16]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 13:25
Оценка:
G>>нет. результат не тот.
G>>у меня все спецификации покрыты тестами. так же есть тесты на репозиторий. все сервисные методы так же покрыты тестами, так как известно какие типы и данные ходят, какие спецификации используются. контроллеры почти не содержат кода и так же легко поддаются тестированию.

Z>Машушвать! Продемонстрируй ка тест на AgeLessThan


а в чем проблема?

var spec = new ActiveUserSpecification();

var result = _users.Where(spec.IsSatisfiedBy());


Z> Ты сам то понял, что сейчас наконец расписался в том, что создал всю эту бодягу только для того, чтобы ее же радостно покрыть тестами?


я её могу покрыть тестами, что и делаю. это условие, часть бизнес логики. логично что на это должны быть тесты. и они есть.
твои методы так же можно покрыть.
но никто не заставляет твоих разработчиков юзать твои методы. они могут идти в обход, делая запросы к IQueriable. у меня не могут. вся разница.

Z> Готов спорить, что у тебя для тестов этой штуки придумана еще очень неслабая инфраструктура для тестирования.


поспорь.
Re[17]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.07.11 15:04
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


G>>Затем что запрос эффективнее строить там где наиболее полно известна информация об этом запросе. А известна она на уровне UI.

G>>Например:
G>>1)Пользователь нажал на страницу 2 в списке каких-то объектов
G>>2)В UI есть информация какой список объектов нужен и что вызвана страница 2
G>>3)Код PL выполняет получение списка объектов из сервиса BL (IQueryable) и выполняет разбивку на страницы .Skip(...).Take(...), накладывает проекции, материализует для передачи UI.
G>>3)Сервис BL получает от Repository IQueryable, фильтрует все Hidden объекты и накладывает предикаты видимости в зависимости от роли пользователя.
G>>4)Repository является тонкой оберткой на ORM, чтобы в тестах его можно было заменить на что-то полегче.

G>>Если не протаскивать IQueryable, то придется "протаскивать" передачу параметров из UI в нижние слои. Причем под каждый набор параметров понадобится свой метод, что приведет у увеличению количества методов, копипасте и другим плохим вещам.


Z>Протаскивается только предикат и протаскивается в одну сторону. Против этого я ничего не имею. Все протаскивание выглядит так PL->BL->DAL.

Покажи как в коде будет выглядеть то что ты предлагаешь. Особенно интересуют проекции.

Z>Обертку ORM для облегчения тестирования, конечно, сделать можно, только зачем называть ее Repository и делать для каждой сущности?

А зачем для каждой сущности? Я примерно вот так делаю.

Z>Я же тестирую такие вещи прямо на базе с тестовыми данными, не идеально, но работает.

Тоже вариант, но писанины больше и работает медленнее.

Z>Заодно позволяет заметить некоторые проблемы производительности.

Тестировать производительность лучше всего на реальных данных, или приближенных к реальным, это уже будут не unit и даже не integration тесты.
Re[17]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.07.11 15:49
Оценка:
Здравствуйте, Gengzu, Вы писали:

G>>>нет. результат не тот.

G>>>у меня все спецификации покрыты тестами. так же есть тесты на репозиторий. все сервисные методы так же покрыты тестами, так как известно какие типы и данные ходят, какие спецификации используются. контроллеры почти не содержат кода и так же легко поддаются тестированию.

Z>>Машушвать! Продемонстрируй ка тест на AgeLessThan


G>а в чем проблема?


G> var spec = new ActiveUserSpecification();


G> var result = _users.Where(spec.IsSatisfiedBy());


А почему бы не

var result = _users.Where(u => u.IsActive)

?

Или еще лучше
var result = _users.Active()

где
public static IQueryable<T> Active(this IQueryable<T> seq) where T:IActivateable, class
{
    return seq.Where(e => e.IsActive);
}

public interface IActivateable
{
    bool IsActive { get; set; }
}

class User: IActivateable //,..
{
    //...
}




Z>> Ты сам то понял, что сейчас наконец расписался в том, что создал всю эту бодягу только для того, чтобы ее же радостно покрыть тестами?


G>я её могу покрыть тестами, что и делаю. это условие, часть бизнес логики. логично что на это должны быть тесты. и они есть.

Не понятно? Ты сделал что-то, покрыл тестами, хотя без этого "что-то" то же самое проверяет компилятор.

G>твои методы так же можно покрыть.

G>но никто не заставляет твоих разработчиков юзать твои методы. они могут идти в обход, делая запросы к IQueriable. у меня не могут. вся разница.

var result = _users.Where(u => u.IsActive)

А result твой какого типа?
Re[6]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.07.11 15:52
Оценка: +1
Здравствуйте, Gengzu, Вы писали:

G>другое дело, если ваше приложение получит доп. уровень абстракции, и данные будут выгребаться через веб-сервисы. в случаи нормального абстрагирования, нужно будет переписать лишь репозитории, и IQueriable там увы не подойдёт.


Тогда много что не подойдет. Если делать веб-сервисы, то сам способ взаимодейтсвия с сервером сильно изменится. Придется реально каждый запрос к серверу считать, не то что запросы к БД.

Кстати для выставления данных через http есть Odata (wcf data services), которые поддерживают IQueryable.
Re[18]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.07.11 16:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>
G>var result = _users.Where(u => u.IsActive)
G>

G>А result твой какого типа?

тьфу, такой код:

var result = _users.Where(spec.IsSatisfiedBy());


Вот какого типа тут result?
Re[18]: Работа с ORM
От: Gengzu  
Дата: 26.07.11 19:43
Оценка:
G>А почему бы не

G>
G>var result = _users.Where(u => u.IsActive)
G>

G>?

G>Или еще лучше

G>
G>var result = _users.Active()
G>

G>где
G>
G>public static IQueryable<T> Active(this IQueryable<T> seq) where T:IActivateable, class
G>{
G>    return seq.Where(e => e.IsActive);
G>}

G>public interface IActivateable
G>{
G>    bool IsActive { get; set; }
G>}

G>class User: IActivateable //,..
G>{
G>    //...
G>}
G>


Если бы ты чуть более внимательно читал тред, ты бы понял, что в твоём случае необходимо предоставлять наружу IQueriable, что есть идеологически плохо.
А так ничего. всё хорошо.


G>>я её могу покрыть тестами, что и делаю. это условие, часть бизнес логики. логично что на это должны быть тесты. и они есть.

G>Не понятно? Ты сделал что-то, покрыл тестами, хотя без этого "что-то" то же самое проверяет компилятор.

Компилятор тут не причем. Этот кусок бизнес логики. на него есть тест.
более того, спецификации могут быть использованы для валидации бизнес объектов.

G>А result твой какого типа?


это кусок из предпологаемого тестового метода, и тип возвращемых данных в данном случае совершенно не имеет значения.
Re[17]: Работа с ORM
От: Ziaw Россия  
Дата: 27.07.11 01:13
Оценка:
Здравствуйте, Gengzu, Вы писали:

Z>>Машушвать! Продемонстрируй ка тест на AgeLessThan


G>а в чем проблема?


G> var spec = new ActiveUserSpecification();


G> var result = _users.Where(spec.IsSatisfiedBy());


1) Без ассерта это не тест.
2) даже если добавить ассерт, это будет не юнит-тест

О каком облегчении тестирования идет речь совершенно не ясно.
Re[18]: Работа с ORM
От: Ziaw Россия  
Дата: 27.07.11 07:15
Оценка:
Здравствуйте, gandjustas, Вы писали:

Z>>Протаскивается только предикат и протаскивается в одну сторону. Против этого я ничего не имею. Все протаскивание выглядит так PL->BL->DAL.

G>Покажи как в коде будет выглядеть то что ты предлагаешь. Особенно интересуют проекции.

Я вообще за простоту и передаю сессию везде где она требуется. Если же физически нет доступа, или очень хочется архитектурно отвязать PL от ORM можно придумать такой вариант:
var pairs = ExecuteQuery<Entity1, Entity2>((e1src, e2src) =>
{
  return from e1 in e1src
  from e2 in e2src
  where e1.Entity2Id = e2.Id
  select new { e1.Id, e2.Name }
})

Никакой сессии для создания в клиентском коде такого запроса не требуется, создается обычный expression. Добавить предикаты к каждой сущности тоже несложно.

Z>>Обертку ORM для облегчения тестирования, конечно, сделать можно, только зачем называть ее Repository и делать для каждой сущности?

G>А зачем для каждой сущности? Я примерно вот так делаю.

Все равно для каждой сущности получается свой тип. Generics или кодогенерация, не суть важно. Так для какой цели оно делается? Только для облегчения тестирования? Цель вобщем-то понятная, только это не является основной целью классического паттерна репозитарий.
Re[19]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.07.11 09:52
Оценка: +1
Здравствуйте, Gengzu, Вы писали:


G>Если бы ты чуть более внимательно читал тред, ты бы понял, что в твоём случае необходимо предоставлять наружу IQueriable, что есть идеологически плохо.

G>А так ничего. всё хорошо.
Идеологические аргументы самые бесполезные. Ибо важны метрики, например если что-то дает меньше кода и его легче поддерживать, то срать я хотел на идеологию, которая что-то запрещает. И вам того же желаю.


G>>>я её могу покрыть тестами, что и делаю. это условие, часть бизнес логики. логично что на это должны быть тесты. и они есть.

G>>Не понятно? Ты сделал что-то, покрыл тестами, хотя без этого "что-то" то же самое проверяет компилятор.

G>Компилятор тут не причем. Этот кусок бизнес логики. на него есть тест.

Если что-то проевяется компилятором, то этому не нужны тесты. Тесты — костыль для того что не проверяет компилятор и другие инструменты статического анализа.

G>более того, спецификации могут быть использованы для валидации бизнес объектов.

Так же как обычные предикаты. Никто ведь не мешает сохранить предикат в переменную и подсовывать его через IoC.

G>>А result твой какого типа?

G>это кусок из предпологаемого тестового метода, и тип возвращемых данных в данном случае совершенно не имеет значения.
Раз уж ушел от ответа, то видимо IQueryable.
А в реальном коде как оно выглядит? Интересно посмотреть на control flow между классами в реальном случае.
Re[19]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.07.11 09:58
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


Z>>>Протаскивается только предикат и протаскивается в одну сторону. Против этого я ничего не имею. Все протаскивание выглядит так PL->BL->DAL.

G>>Покажи как в коде будет выглядеть то что ты предлагаешь. Особенно интересуют проекции.

Z>Я вообще за простоту и передаю сессию везде где она требуется. Если же физически нет доступа, или очень хочется архитектурно отвязать PL от ORM можно придумать такой вариант:

Z>
Z>var pairs = ExecuteQuery<Entity1, Entity2>((e1src, e2src) =>
Z>{
Z>  return from e1 in e1src
Z>  from e2 in e2src
Z>  where e1.Entity2Id = e2.Id
Z>  select new { e1.Id, e2.Name }
Z>})
Z>

Z>Никакой сессии для создания в клиентском коде такого запроса не требуется, создается обычный expression. Добавить предикаты к каждой сущности тоже несложно.

Чем это лучше обычного вызова Select? ты ведь все равно пишешь Linq со всеми вытекающими последствиями, о которых говорят другие ораторы.

Z>>>Обертку ORM для облегчения тестирования, конечно, сделать можно, только зачем называть ее Repository и делать для каждой сущности?

G>>А зачем для каждой сущности? Я примерно вот так делаю.

Z>Все равно для каждой сущности получается свой тип. Generics или кодогенерация, не суть важно. Так для какой цели оно делается? Только для облегчения тестирования?

Да, именно так. Причем в последних версиях EF и такое писать не нужно, есть IObjectSet.

Z>Цель вобщем-то понятная, только это не является основной целью классического паттерна репозитарий.

"Классический паттерн репозитарий" был придуман в 90-х годах прошлого века. Важно за всеми sequence и другими диаграммами понимать суть. А суть заключается в том что репозиторй должен отдавать данные в зависимости от некоторого query object. Чтобы репозиторий при желании можно было подменить. В данном случае что-то типа IObjectSet более чем достаточно.
Re[20]: Работа с ORM
От: Ziaw Россия  
Дата: 27.07.11 10:35
Оценка:
Здравствуйте, gandjustas, Вы писали:

Z>>Я вообще за простоту и передаю сессию везде где она требуется. Если же физически нет доступа, или очень хочется архитектурно отвязать PL от ORM можно придумать такой вариант:

Z>>
Z>>var pairs = ExecuteQuery<Entity1, Entity2>((e1src, e2src) =>
Z>>{
Z>>  return from e1 in e1src
Z>>  from e2 in e2src
Z>>  where e1.Entity2Id = e2.Id
Z>>  select new { e1.Id, e2.Name }
Z>>})
Z>>

Z>>Никакой сессии для создания в клиентском коде такого запроса не требуется, создается обычный expression. Добавить предикаты к каждой сущности тоже несложно.

G>Чем это лучше обычного вызова Select? ты ведь все равно пишешь Linq со всеми вытекающими последствиями, о которых говорят другие ораторы.


Ответ на вопрос я дал. На всякий случай выделил. Последствия других ораторов на фоне предлагаемых альтернатив безмерно доставляют.

G>А суть заключается в том что репозиторй должен отдавать данные в зависимости от некоторого query object. Чтобы репозиторий при желании можно было подменить.


Ты делаешь обычный адаптер. Нормальное решение против которого я ничего не имею. А то, что репозитарий давно морально устарел, я и пытаюсь тут объяснить.

Суть его по Фаулеру:

build another layer of abstraction over the mapping layer where query construction code is concentrated.

Убери эту суть, останется голый адаптер для уменьшения связанности и облегчения тестирования. Никак не связанный с БД или еще чем-то.

Несмотря на устаревание, неокрепшие умы начитавшись Фаулера пытаются заюзать сразу все паттерны из книжки в надежде на то, что программистам в хиторосплетении этой архитектуры негде будет делать ошибки.
Re[21]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.07.11 13:55
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


Z>>>Я вообще за простоту и передаю сессию везде где она требуется. Если же физически нет доступа, или очень хочется архитектурно отвязать PL от ORM можно придумать такой вариант:

Z>>>
Z>>>var pairs = ExecuteQuery<Entity1, Entity2>((e1src, e2src) =>
Z>>>{
Z>>>  return from e1 in e1src
Z>>>  from e2 in e2src
Z>>>  where e1.Entity2Id = e2.Id
Z>>>  select new { e1.Id, e2.Name }
Z>>>})
Z>>>

Z>>>Никакой сессии для создания в клиентском коде такого запроса не требуется, создается обычный expression. Добавить предикаты к каждой сущности тоже несложно.

G>>Чем это лучше обычного вызова Select? ты ведь все равно пишешь Linq со всеми вытекающими последствиями, о которых говорят другие ораторы.


Z>Ответ на вопрос я дал. На всякий случай выделил. Последствия других ораторов на фоне предлагаемых альтернатив безмерно доставляют.


Насколько я понимаю доводы противников IQueryable заключаются в том что для IQueryable можно написать любой запрос в том числе заведомо неэффективный и\или противоречащий БЛ. Получать или не получать session или любой другой объект "соединения с бд" тут разницы не имеет.

G>>А суть заключается в том что репозиторй должен отдавать данные в зависимости от некоторого query object. Чтобы репозиторий при желании можно было подменить.


Z>Ты делаешь обычный адаптер. Нормальное решение против которого я ничего не имею. А то, что репозитарий давно морально устарел, я и пытаюсь тут объяснить.

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

Z>Суть его по Фаулеру:

Z>

Z>build another layer of abstraction over the mapping layer where query construction code is concentrated.

Z>Убери эту суть, останется голый адаптер для уменьшения связанности и облегчения тестирования. Никак не связанный с БД или еще чем-то.
Я бы все таки обратил внимание на то что он пишет в PoEAA. Там нету модного нынче популяризторства DDD и других аббривеатур.
Re[22]: Работа с ORM
От: Ziaw Россия  
Дата: 27.07.11 15:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Насколько я понимаю доводы противников IQueryable заключаются в том что для IQueryable можно написать любой запрос в том числе заведомо неэффективный и\или противоречащий БЛ. Получать или не получать session или любой другой объект "соединения с бд" тут разницы не имеет.


Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья. С "другими ораторами" я уже не знаю о чем говорить. Ты тоже считаешь, что проблему неэффективных запросов можно решить заменив expression tree на свое самопальное query tree? Я так считаю, что чем проще программисту строить запрос, чем прозрачнее он видит SQL за ним, тем запросы будут эффективнее. Самые эффективные запросы будут если программист их будет писать напрямую в коде, но там возникнут другие серьезные проблемы. И наоборот, чем больше абстракций навешать между базой и бизнес логикой, тем менее эффективно будет использоваться база.

G>Я бы все таки обратил внимание на то что он пишет в PoEAA. Там нету модного нынче популяризторства DDD и других аббривеатур.


Вот тут должна быть цитата из того, что он пишет в PoEAA, но ее почему-то нет. Читал я ее очень давно и представление сейчас имею довольно общее. То, что репозитарий там несколько больше тривиального адаптера к ORM у меня особых сомнений нет, но чем черт не шутит. Тем не менее перечитывать не буду, врядли уже вынесу что-то новое.
Re[23]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 28.07.11 09:38
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


G>>Насколько я понимаю доводы противников IQueryable заключаются в том что для IQueryable можно написать любой запрос в том числе заведомо неэффективный и\или противоречащий БЛ. Получать или не получать session или любой другой объект "соединения с бд" тут разницы не имеет.


Z>Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья.

Дык ты не избавился, ты только скрыл его в методе, но точно так же пишешь expression tree, в который передаешь параметры через замыкания.

Z>Ты тоже считаешь, что проблему неэффективных запросов можно решить заменив expression tree на свое самопальное query tree?

Я вообще не читают проблемой использовать IQueryable где нужно.

G>>Я бы все таки обратил внимание на то что он пишет в PoEAA. Там нету модного нынче популяризторства DDD и других аббривеатур.

Z>Вот тут должна быть цитата из того, что он пишет в PoEAA, но ее почему-то нет. Читал я ее очень давно и представление сейчас имею довольно общее. То, что репозитарий там несколько больше тривиального адаптера к ORM у меня особых сомнений нет, но чем черт не шутит. Тем не менее перечитывать не буду, врядли уже вынесу что-то новое.

У меня под рукой к сожалению нет книжки.
Re[24]: Работа с ORM
От: Ziaw Россия  
Дата: 28.07.11 16:58
Оценка:
Здравствуйте, gandjustas, Вы писали:

Z>>Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья.

G>Дык ты не избавился, ты только скрыл его в методе, но точно так же пишешь expression tree, в который передаешь параметры через замыкания.

Да нет же, фича как раз в том, что контекст соединения тут не нужен. Сформированное expression tree можно передать за границу процесса.

G>Я вообще не читают проблемой использовать IQueryable где нужно.


Re[25]: Работа с ORM
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.07.11 15:30
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


Z>>>Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья.

G>>Дык ты не избавился, ты только скрыл его в методе, но точно так же пишешь expression tree, в который передаешь параметры через замыкания.

Z>Да нет же, фича как раз в том, что контекст соединения тут не нужен. Сформированное expression tree можно передать за границу процесса.


В общем случае нельзя, а в частном случае пофиг есть контекст или нет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.