Здравствуйте, Gengzu, Вы писали:
G>другое дело, если ваше приложение получит доп. уровень абстракции, и данные будут выгребаться через веб-сервисы. в случаи нормального абстрагирования, нужно будет переписать лишь репозитории, и IQueriable там увы не подойдёт.
Тогда много что не подойдет. Если делать веб-сервисы, то сам способ взаимодейтсвия с сервером сильно изменится. Придется реально каждый запрос к серверу считать, не то что запросы к БД.
Кстати для выставления данных через http есть Odata (wcf data services), которые поддерживают IQueryable.
Если бы ты чуть более внимательно читал тред, ты бы понял, что в твоём случае необходимо предоставлять наружу IQueriable, что есть идеологически плохо.
А так ничего. всё хорошо.
G>>я её могу покрыть тестами, что и делаю. это условие, часть бизнес логики. логично что на это должны быть тесты. и они есть. G>Не понятно? Ты сделал что-то, покрыл тестами, хотя без этого "что-то" то же самое проверяет компилятор.
Компилятор тут не причем. Этот кусок бизнес логики. на него есть тест.
более того, спецификации могут быть использованы для валидации бизнес объектов.
G>А result твой какого типа?
это кусок из предпологаемого тестового метода, и тип возвращемых данных в данном случае совершенно не имеет значения.
Здравствуйте, Gengzu, Вы писали:
Z>>Машушвать! Продемонстрируй ка тест на AgeLessThan
G>а в чем проблема?
G> var spec = new ActiveUserSpecification();
G> var result = _users.Where(spec.IsSatisfiedBy());
1) Без ассерта это не тест.
2) даже если добавить ассерт, это будет не юнит-тест
О каком облегчении тестирования идет речь совершенно не ясно.
Здравствуйте, 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 или кодогенерация, не суть важно. Так для какой цели оно делается? Только для облегчения тестирования? Цель вобщем-то понятная, только это не является основной целью классического паттерна репозитарий.
G>Если бы ты чуть более внимательно читал тред, ты бы понял, что в твоём случае необходимо предоставлять наружу IQueriable, что есть идеологически плохо. G>А так ничего. всё хорошо.
Идеологические аргументы самые бесполезные. Ибо важны метрики, например если что-то дает меньше кода и его легче поддерживать, то срать я хотел на идеологию, которая что-то запрещает. И вам того же желаю.
G>>>я её могу покрыть тестами, что и делаю. это условие, часть бизнес логики. логично что на это должны быть тесты. и они есть. G>>Не понятно? Ты сделал что-то, покрыл тестами, хотя без этого "что-то" то же самое проверяет компилятор.
G>Компилятор тут не причем. Этот кусок бизнес логики. на него есть тест.
Если что-то проевяется компилятором, то этому не нужны тесты. Тесты — костыль для того что не проверяет компилятор и другие инструменты статического анализа.
G>более того, спецификации могут быть использованы для валидации бизнес объектов.
Так же как обычные предикаты. Никто ведь не мешает сохранить предикат в переменную и подсовывать его через IoC.
G>>А result твой какого типа? G>это кусок из предпологаемого тестового метода, и тип возвращемых данных в данном случае совершенно не имеет значения.
Раз уж ушел от ответа, то видимо IQueryable.
А в реальном коде как оно выглядит? Интересно посмотреть на control flow между классами в реальном случае.
Здравствуйте, 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 более чем достаточно.
Здравствуйте, 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.
Убери эту суть, останется голый адаптер для уменьшения связанности и облегчения тестирования. Никак не связанный с БД или еще чем-то.
Несмотря на устаревание, неокрепшие умы начитавшись Фаулера пытаются заюзать сразу все паттерны из книжки в надежде на то, что программистам в хиторосплетении этой архитектуры негде будет делать ошибки.
Здравствуйте, 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 и других аббривеатур.
Здравствуйте, gandjustas, Вы писали:
G>Насколько я понимаю доводы противников IQueryable заключаются в том что для IQueryable можно написать любой запрос в том числе заведомо неэффективный и\или противоречащий БЛ. Получать или не получать session или любой другой объект "соединения с бд" тут разницы не имеет.
Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья. С "другими ораторами" я уже не знаю о чем говорить. Ты тоже считаешь, что проблему неэффективных запросов можно решить заменив expression tree на свое самопальное query tree? Я так считаю, что чем проще программисту строить запрос, чем прозрачнее он видит SQL за ним, тем запросы будут эффективнее. Самые эффективные запросы будут если программист их будет писать напрямую в коде, но там возникнут другие серьезные проблемы. И наоборот, чем больше абстракций навешать между базой и бизнес логикой, тем менее эффективно будет использоваться база.
G>Я бы все таки обратил внимание на то что он пишет в PoEAA. Там нету модного нынче популяризторства DDD и других аббривеатур.
Вот тут должна быть цитата из того, что он пишет в PoEAA, но ее почему-то нет. Читал я ее очень давно и представление сейчас имею довольно общее. То, что репозитарий там несколько больше тривиального адаптера к ORM у меня особых сомнений нет, но чем черт не шутит. Тем не менее перечитывать не буду, врядли уже вынесу что-то новое.
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, gandjustas, Вы писали:
G>>Насколько я понимаю доводы противников IQueryable заключаются в том что для IQueryable можно написать любой запрос в том числе заведомо неэффективный и\или противоречащий БЛ. Получать или не получать session или любой другой объект "соединения с бд" тут разницы не имеет.
Z>Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья.
Дык ты не избавился, ты только скрыл его в методе, но точно так же пишешь expression tree, в который передаешь параметры через замыкания.
Z>Ты тоже считаешь, что проблему неэффективных запросов можно решить заменив expression tree на свое самопальное query tree?
Я вообще не читают проблемой использовать IQueryable где нужно.
G>>Я бы все таки обратил внимание на то что он пишет в PoEAA. Там нету модного нынче популяризторства DDD и других аббривеатур. Z>Вот тут должна быть цитата из того, что он пишет в PoEAA, но ее почему-то нет. Читал я ее очень давно и представление сейчас имею довольно общее. То, что репозитарий там несколько больше тривиального адаптера к ORM у меня особых сомнений нет, но чем черт не шутит. Тем не менее перечитывать не буду, врядли уже вынесу что-то новое.
Здравствуйте, gandjustas, Вы писали:
Z>>Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья. G>Дык ты не избавился, ты только скрыл его в методе, но точно так же пишешь expression tree, в который передаешь параметры через замыкания.
Да нет же, фича как раз в том, что контекст соединения тут не нужен. Сформированное expression tree можно передать за границу процесса.
G>Я вообще не читают проблемой использовать IQueryable где нужно.
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, gandjustas, Вы писали:
Z>>>Другие ораторы говорят странные вещи. Я тебе отвечал на вопрос, как можно избавиться от протаскивания контекста через все слои, особенно если они вдруг превращаются в звенья. G>>Дык ты не избавился, ты только скрыл его в методе, но точно так же пишешь expression tree, в который передаешь параметры через замыкания.
Z>Да нет же, фича как раз в том, что контекст соединения тут не нужен. Сформированное expression tree можно передать за границу процесса.
В общем случае нельзя, а в частном случае пофиг есть контекст или нет.