Re[6]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 18:28
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


НС>>>Сейчас, в принципе, ни одна ORM не доросла до уровня, который позволит абстрагироваться от ее специфики. Так что попытка такую абстракцию ввести — классический случай leaky abstraction со всеми вытекающими.


G>>Дело не в конкретных ORM

НС>Конечно не в конкретных. Потому что ровно 100% ORM не способны полностью спрятать детали реализации. Причем с тяжелыми ORM вообще сразу все понятно. Из легковесных linq2db продвинулась дальше всего, но и там такое море специфики, что о полной абстракции не приходится даже мечтать. Итого, нетекущая абстракция сейчас возможна только на уровне самых простых запросов с явными джойнами.
Что ты понимаешь под "полной абстракциией" ? Даже если на уровне синтаксиса запросов к БД привести все к общему знаменателю, то на уровне семантики и быстродействия все равно найдутся различия. А попытка сделать объектную обертку над ОРМ ни к чему хорошему не приводит.

G>>SQL очень выразительный язык, гораздо выразительнее любого мейнстримного языка,


НС>Чего? Я тебе как садовод могу сказать, что даже та выразительность, что дает expression tree в шарпе на голову выше, чем выразительность SQL. Потому что постоянно приходится сталкиваться с ситуацией, когда тривиальное выражение на linq невозможно или очень сложно оттранслировать в SQL. Банальный group by порой таких жестких приседаний на sql требует, что в пору застрелиться.

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

SQL (на примере TSQL) умеет, а Linq нет:
1) CTE и рекурсию
2) ranking-функции и агрегаты с partition
3) MERGE-оператор
4) PIVOT\UNPIVOT

G>> Linq создавался как раз чтобы не сильно отставать по выразительности от SQL.

НС>Это ты сам придумал?
Нет, об этом Мейер говорил. Он еще в Haskell такое изобретал.


G>>Вот Синклер рассказывал к чему приводит "абстрагирование" http://rsdn.ru/forum/design/5682243
Автор: Sinclair
Дата: 10.07.14

НС>Он то расказал правильно, а вот ты понял его как то странно, судя по всему.
А ты тогда о чем говоришь?
Различия в СУБД не позволяют эффективно построить один API для любой СУБД. А Linq в этих случаях как раз и используется как генератор СУБД-специфичных запросов.
Re[13]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 18:40
Оценка:
Здравствуйте, Vladek, Вы писали:

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


V>>>Это зона ответственности репозитория, а снаружи ничего не известно и потому одну реализацию легко заменить на другую.

G>>Это в теории.

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

G>>И вот нам надо получить самые популярные посты за день. Для этого надо "всего лишь" пробежать по всем постам и посчитать оценку за день. Когда постов станет пару тысяч это перестанет работать.
G>>Чтобы оно работало надо будет написать фоновый процесс, который при добавлении оценки будет считать оценку за день и обновлять список лучших постов.

V>Нет, надо выбросить код с текстовыми файлами и написать код, работающий с БД.


Не понял фразы. Кому надо? Куда выбросить? Вот я тебе привет пример кода, который с субд работает. Ты предположил что репозиторий поможет "одну реализацию легко заменить на другую" и сам привел пример с файлами. В результате поменять субд на файлы окажется совсем нелегко, несмотря на репозитарии.

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

V>Что изменится в контракте репозитория? Правильно, ничего.

Даже если переписать весь контракт репозитария изменится 4-5 строк в методах, которые взывают этот репзитарий, по сравнению с написанием джоба по вычислению топовых постов, эти изменения не будут видны в микроскоп.


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

G>>Тогда зачем прятать Linq внутри репозитария, если можно IQueryable<T> отдать потребителю, а специфичные вещи спрятать в комбинаторы.

V>Потому что внешний мир обходится IEnumerable, отфильтрованным, отсортированным и порезанным на странички.

Ну ок, сделай все что надо непосредственно перед отдачей во внешний мир (в рендеринг страницы). Зачем тебе репозиторий?

V>ORM отдают IQueryable внешнему миру, а мы не пишем ORM, мы пишем репозиторий. Для нашего ORM весь внешний мир ограничивается репозиторием. А это значит, пользователь репозитория не имеет доступа к объектам ORM, которые маппятся из БД — нечего выдавать в качестве T для IQueryable<T>.

И какой в этом смысл? То что оно усложняет код я уже увидел, а где положительные эффекты?

V>>>Вместо строк можно использовать другие объекты, никаких ограничивающих правил нет.

G>>Какие например? Ну чтобы получить тот же уровень контроля компилятором, как в случае Linq.
V>PostSortingMethod.
Что это? Пример кода приведи.

V>>>Тогда сортировка просто не будет работать как надо, программист быстро укажет то, что нужно, и всё заработает.

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

V>Ещё программить может привести IQueryable к IEnumerable, отсортировать и в цикле выбрать нужные объекты. Компилятор с радостью это скомпилирует. И оно даже будет работать быстро некоторое время.

А кто мешает сделать программисту тоже самое с IEnumerable? Или ты думаешь, что если ты отдаешь IEnumerable. то никто к нему Linq применить не сможет, родив очень неэффективный код? Кстати именно поэтому имеет смысл отдавать Iqueryable, ибо тогда Linq превратится в запрос и улетит в базу, а привести к IEnumerable еще и не каждый догадается.
Re[14]: Entity Framework за! и против!
От: Vladek Россия Github
Дата: 18.08.14 19:15
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


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


V>>>>Это зона ответственности репозитория, а снаружи ничего не известно и потому одну реализацию легко заменить на другую.

G>>>Это в теории.

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

G>>>И вот нам надо получить самые популярные посты за день. Для этого надо "всего лишь" пробежать по всем постам и посчитать оценку за день. Когда постов станет пару тысяч это перестанет работать.
G>>>Чтобы оно работало надо будет написать фоновый процесс, который при добавлении оценки будет считать оценку за день и обновлять список лучших постов.

V>>Нет, надо выбросить код с текстовыми файлами и написать код, работающий с БД.


G>Не понял фразы. Кому надо? Куда выбросить? Вот я тебе привет пример кода, который с субд работает. Ты предположил что репозиторий поможет "одну реализацию легко заменить на другую" и сам привел пример с файлами. В результате поменять субд на файлы окажется совсем нелегко, несмотря на репозитарии.


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

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

V>>Что изменится в контракте репозитория? Правильно, ничего.
G>
G>Даже если переписать весь контракт репозитария изменится 4-5 строк в методах, которые взывают этот репзитарий, по сравнению с написанием джоба по вычислению топовых постов, эти изменения не будут видны в микроскоп.

Контракт репозитория оперирует объектами из модели данных программы и они не будут затронуты изменениями в стратегии хранения данных.

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

G>>>Тогда зачем прятать Linq внутри репозитария, если можно IQueryable<T> отдать потребителю, а специфичные вещи спрятать в комбинаторы.

V>>Потому что внешний мир обходится IEnumerable, отфильтрованным, отсортированным и порезанным на странички.

G>Ну ок, сделай все что надо непосредственно перед отдачей во внешний мир (в рендеринг страницы). Зачем тебе репозиторий?

Этим и занимается репозиторий — выборкой данных — дальше не его забота куда данные отправляются.

V>>ORM отдают IQueryable внешнему миру, а мы не пишем ORM, мы пишем репозиторий. Для нашего ORM весь внешний мир ограничивается репозиторием. А это значит, пользователь репозитория не имеет доступа к объектам ORM, которые маппятся из БД — нечего выдавать в качестве T для IQueryable<T>.

G>И какой в этом смысл? То что оно усложняет код я уже увидел, а где положительные эффекты?

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

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

V>>>>Вместо строк можно использовать другие объекты, никаких ограничивающих правил нет.

G>>>Какие например? Ну чтобы получить тот же уровень контроля компилятором, как в случае Linq.
V>>PostSortingMethod.
G>Что это? Пример кода приведи.

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

V>>>>Тогда сортировка просто не будет работать как надо, программист быстро укажет то, что нужно, и всё заработает.

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

V>>Ещё программить может привести IQueryable к IEnumerable, отсортировать и в цикле выбрать нужные объекты. Компилятор с радостью это скомпилирует. И оно даже будет работать быстро некоторое время.

G>А кто мешает сделать программисту тоже самое с IEnumerable? Или ты думаешь, что если ты отдаешь IEnumerable. то никто к нему Linq применить не сможет, родив очень неэффективный код? Кстати именно поэтому имеет смысл отдавать Iqueryable, ибо тогда Linq превратится в запрос и улетит в базу, а привести к IEnumerable еще и не каждый догадается.

Этот IEnumerable будет содержать с десяток объектов, уже готовых для отображения пользователю. Любые манипуляции с ним не будут отличаться большими накладными расходами.
Re[7]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 18.08.14 19:26
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Что ты понимаешь под "полной абстракциией" ?


Чтобы писать код не задумываясь о деталях реализации ORM. Сейчас таких ORM нет.

G>То что можно больше написать не означает что выразительность выше.


Как раз таки означает.

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


Перл элементарно транслируется в банальный плоский С. Так что негодная у тебя аналогия. Проблема не в транслируемости конструкций, а в том что вполне осмысленные, нормально выглядящие и работающие на linq2objects конструкции на SQL фик переведешь.

G>SQL (на примере TSQL) умеет, а Linq нет:

G>1) CTE и рекурсию

СТЕ сама по себе линку просто не нужна. А поддердка рекурсии — вопрос конкретных провайдеров, которым просто никто не занимался всерьез.

G>2) ranking-функции и агрегаты с partition


Это вообще не проблема.

G>3) MERGE-оператор


Тоже не проблема.

G>4) PIVOT\UNPIVOT


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

G>>> Linq создавался как раз чтобы не сильно отставать по выразительности от SQL.

НС>>Это ты сам придумал?
G>Нет, об этом Мейер говорил.

Эрик? Ссылку можно? А то я немножко на эту тему с ним общался, и ничего подобного не услышал.

НС>>Он то расказал правильно, а вот ты понял его как то странно, судя по всему.

G>А ты тогда о чем говоришь?

Я, кажется, вполне понятно написал. Любая ОРМ, если попытаться от нее абстрагироваться, приведет к leaky abstraction. Без вариантов. Что тебе в этом утверждении непонятно?

G>Различия в СУБД не позволяют эффективно построить один API для любой СУБД. А Linq в этих случаях как раз и используется как генератор СУБД-специфичных запросов.
Re[11]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 18.08.14 19:26
Оценка:
Здравствуйте, Vladek, Вы писали:

НС>>Т.е., получаем, на каждый запрос я создаю отдельный метод выборки, который будет использоваться ровно в одном месте? Ну и ради чего? Чтобы когда нибудь БД заменить на текстовый файл?


V>Чтобы код был простым


То есть ты считаешь, что если вместо просто запроса будет запрос + руками описанный набор DTO + публичный интерфейс + вызов метода, то это будет более простой код?

V>и его было легко расширять и менять.


Т.е. ты считаешь, что расширять просто запрос сложнее, чем запрос + руками описанный набор DTO + публичный интерфейс + вызов метода? Сможешь аргументировать?
Re[7]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 18.08.14 19:26
Оценка:
Здравствуйте, Vladek, Вы писали:

НС>>Куда интереснее что ты делаешь, когда в одном месте нужны посты с рейтингом, а в другом без, или в одном месте достаточно имени автора, а в другом потребно пяток полей из его профиля?


V>Просто делаю параметры выборки в виде Nullable.


Подожди, а с джойнами как? Заранее втыкиваешь ссылки и коллекции на все теоретически возможные джойны? ИМ потом таскаешь везде этот мегакласс, полагаясь на авость что никто в клиентском коде не дернет поля, в которые данные не запихнуты?

V>На моей практике таких полей редко больше четырёх.


А на моей практике и пару десятков не редкость.

V> Пользователи не очень любят заполнять формы со 100500 полями.


Далеко не всегда соотношение полей формы и полей в таблице 1 к 1.
Re[15]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 18.08.14 19:39
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Если все детали того, как репозиторий хранит данные, скрыты, то мы можем легко сменить файлы на субд и наоборот.


Повторяю вопрос — тебе хотя бы раз такое понадобилось? Мне вот, за 18 лет стажа, большая часть которого связана с БД, не понадобилось ни разу. Но если вдруг понадобится — тоже не проблема. Придется только поправить неймспейсы и перекомпилировать, чтобы ET заменилось на лямбды.

V>Положительные эффекты в разделении зон ответственности кода. Если тебе надо работать с кодом доступа к бд, ты делаешь это в одном месте и не тебе не приходится лазать по всему дереву исходников.


В случае линка код доступа в БД ты вообще не пишешь. Нигде. Ты просто декларативно описываешь, что тебе надо.
Re[8]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 20:07
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


G>>Что ты понимаешь под "полной абстракциией" ?


НС>Чтобы писать код не задумываясь о деталях реализации ORM. Сейчас таких ORM нет.


В первую очередь нужно задумываться о той СУБД, для которой пишешь. Это уже не дает возможности полностью абстрагироваться.

G>>То что можно больше написать не означает что выразительность выше.

НС>Как раз таки означает.

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

НС>Перл элементарно транслируется в банальный плоский С. Так что негодная у тебя аналогия.
Любой императивный язык транслируется в C. Даже SQL транслируется в C. Это не говорит о выразительности.

НС>Проблема не в транслируемости конструкций, а в том что вполне осмысленные, нормально выглядящие и работающие на linq2objects конструкции на SQL фик переведешь.

Обратное также верно. Если мы говорим о работе с данными в СУБД, то linq менее выразителен, чем SQL.

G>>SQL (на примере TSQL) умеет, а Linq нет:

G>>1) CTE и рекурсию
НС>СТЕ сама по себе линку просто не нужна. А поддердка рекурсии — вопрос конкретных провайдеров, которым просто никто не занимался всерьез.
В linq нет средств для рекурсии.

G>>2) ranking-функции и агрегаты с partition

НС>Это вообще не проблема.

G>>3) MERGE-оператор

НС>Тоже не проблема.

Что значит "не проблема" ?
Как можно написать в Linq простое выражения вроде:
select rank() over (partition by customerid order by orderdate  desc) as r, sum() over (partition by customerid order by orderdate desc) from orders

Увы в linq таких средств нет


G>>4) PIVOT\UNPIVOT

НС>Опять же вопрос конкретного провайдера. Выразительных функций линка хватает за глаза.
НС>При этом есть несколько моментов, которые действительно несколько фигово в линке выражаются по сравнению с сиквелом. Но ни один из них ты не упомянул.
То что ты не видишь не значит что их нет.

G>>>> Linq создавался как раз чтобы не сильно отставать по выразительности от SQL.

НС>>>Это ты сам придумал?
G>>Нет, об этом Мейер говорил.
НС>Эрик? Ссылку можно? А то я немножко на эту тему с ним общался, и ничего подобного не услышал.
Это очень давно было, сейчас не найду даже.

НС>>>Он то расказал правильно, а вот ты понял его как то странно, судя по всему.

G>>А ты тогда о чем говоришь?
НС>Я, кажется, вполне понятно написал. Любая ОРМ, если попытаться от нее абстрагироваться, приведет к leaky abstraction. Без вариантов. Что тебе в этом утверждении непонятно?
ты отвечаешь не на то, что я писал.
Я говорил что нет смысла абстрагироваться, так как приложение обычно затачивается на работу с конкретной СУБД.
Re[15]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 20:29
Оценка:
Здравствуйте, Vladek, Вы писали:

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


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


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


V>>>>>Это зона ответственности репозитория, а снаружи ничего не известно и потому одну реализацию легко заменить на другую.

G>>>>Это в теории.

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

G>>>>И вот нам надо получить самые популярные посты за день. Для этого надо "всего лишь" пробежать по всем постам и посчитать оценку за день. Когда постов станет пару тысяч это перестанет работать.
G>>>>Чтобы оно работало надо будет написать фоновый процесс, который при добавлении оценки будет считать оценку за день и обновлять список лучших постов.

V>>>Нет, надо выбросить код с текстовыми файлами и написать код, работающий с БД.


G>>Не понял фразы. Кому надо? Куда выбросить? Вот я тебе привет пример кода, который с субд работает. Ты предположил что репозиторий поможет "одну реализацию легко заменить на другую" и сам привел пример с файлами. В результате поменять субд на файлы окажется совсем нелегко, несмотря на репозитарии.


V>Если все детали того, как репозиторий хранит данные, скрыты, то мы можем легко сменить файлы на субд и наоборот. Даже если это будет тяжёлая работа, торгать код за пределами репозиториев нам не понадобится.

Файл на субд — легко, наоборот — нет. Слишком много надо написать, чтобы с помощью файлов отвечать на запросы как СУБД. То есть если ты начинаешь проект в котором будет работа с субд, то репозитарий не дает ничего.

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

V>>>Что изменится в контракте репозитория? Правильно, ничего.
G>>
G>>Даже если переписать весь контракт репозитария изменится 4-5 строк в методах, которые взывают этот репзитарий, по сравнению с написанием джоба по вычислению топовых постов, эти изменения не будут видны в микроскоп.

V>Контракт репозитория оперирует объектами из модели данных программы и они не будут затронуты изменениями в стратегии хранения данных.

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

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

G>>>>Тогда зачем прятать Linq внутри репозитария, если можно IQueryable<T> отдать потребителю, а специфичные вещи спрятать в комбинаторы.

V>>>Потому что внешний мир обходится IEnumerable, отфильтрованным, отсортированным и порезанным на странички.

G>>Ну ок, сделай все что надо непосредственно перед отдачей во внешний мир (в рендеринг страницы). Зачем тебе репозиторий?
V>Этим и занимается репозиторий — выборкой данных — дальше не его забота куда данные отправляются.
Это не является ответом на вопрос зачем он нужен. Ты можешь миллион классов придумать, со своими функциями, но это не оправдывает их существования.
Тем более реальной выборкой данных нанимается ORM, а репозиторий только обертка, которая ничего положительного не приносит в код.


V>>>ORM отдают IQueryable внешнему миру, а мы не пишем ORM, мы пишем репозиторий. Для нашего ORM весь внешний мир ограничивается репозиторием. А это значит, пользователь репозитория не имеет доступа к объектам ORM, которые маппятся из БД — нечего выдавать в качестве T для IQueryable<T>.

G>>И какой в этом смысл? То что оно усложняет код я уже увидел, а где положительные эффекты?
V>Код должен делать работу здесь и сейчас (для твоего работодателя и заказчика), код должен легко поддаваться изменениям и оставаться полезным (для тебя в будущем).
И как это онсоится к репозитарию?
"Здесь и сейчас" можно добиться, написав Linq прямо в контроллере. А "легко поддаваться изменениям и оставаться полезным" можно добиться сделав комбинаторы, примерно вот так: http://gandjustas.blogspot.ru/2010/05/iqueryable-generics.html?&amp;tpwf_mode=main
А какая польза от репозитория?

V>Положительные эффекты в разделении зон ответственности кода. Если тебе надо работать с кодом доступа к бд, ты делаешь это в одном месте и не тебе не приходится лазать по всему дереву исходников. В будущем, тебе не придётся долго искать этот код и потом читать половину проекта, чтобы внести изменения и быть уверенным, что ничего не забыто.

Весь код работы с БД находится в ORM, а запросы "в одном месте" это фантастика, потому что в каждом контроллере нужны разные запросы. Где-то нужны сортировки, где-то проекции итп. Очень редко запросы дублируются.

V>>>>>Вместо строк можно использовать другие объекты, никаких ограничивающих правил нет.

G>>>>Какие например? Ну чтобы получить тот же уровень контроля компилятором, как в случае Linq.
V>>>PostSortingMethod.
G>>Что это? Пример кода приведи.

V>Был выше. Это перечисление способов сортировки постов, репозиторий их отсортирует в зависимости от заданного значения этого параметра.

Я уже писал, что это даже хуже разных методов. А преимуществ не вижу.

V>Да, ты можешь попробовать пилить японской пилой рельсу вместо сосны и пила обязательно сломается. Лучше всё же пилить сосну.

Доказательство по аналогии? Тут профессиональный форум, такая демагогия не катит.

V>>>>>Тогда сортировка просто не будет работать как надо, программист быстро укажет то, что нужно, и всё заработает.

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

V>>>Ещё программить может привести IQueryable к IEnumerable, отсортировать и в цикле выбрать нужные объекты. Компилятор с радостью это скомпилирует. И оно даже будет работать быстро некоторое время.

G>>А кто мешает сделать программисту тоже самое с IEnumerable? Или ты думаешь, что если ты отдаешь IEnumerable. то никто к нему Linq применить не сможет, родив очень неэффективный код? Кстати именно поэтому имеет смысл отдавать Iqueryable, ибо тогда Linq превратится в запрос и улетит в базу, а привести к IEnumerable еще и не каждый догадается.

V>Этот IEnumerable будет содержать с десяток объектов, уже готовых для отображения пользователю. Любые манипуляции с ним не будут отличаться большими накладными расходами.

А где гарантия что десятки?
Откуда репозиторий узнает что нужно для отображения пользователю?

С такими рассуждениями у тебя вся логика уедет в репозитории и методы репозиториев будут 1-в-1 повторять контроллеры. А проблемы никуда не денутся.
Re[9]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 18.08.14 21:28
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

НС>>Чтобы писать код не задумываясь о деталях реализации ORM. Сейчас таких ORM нет.

G>В первую очередь нужно задумываться о той СУБД, для которой пишешь.

И это тоже. Но, по опыту, работать на разных СУБД все таки намного проще, чем работать на разных ORM. Первое у меня еще получалось, а вот второе — никогда. Даже переезд с blt linq на linq2db на крупных проектах совсем нетривиальная задача.

НС>>Проблема не в транслируемости конструкций, а в том что вполне осмысленные, нормально выглядящие и работающие на linq2objects конструкции на SQL фик переведешь.

G>Обратное также верно.

Да не особо. Приведенные тобой примере это точно не доказывают.

НС>>СТЕ сама по себе линку просто не нужна. А поддердка рекурсии — вопрос конкретных провайдеров, которым просто никто не занимался всерьез.

G>В linq нет средств для рекурсии.

Т.е. с CTE без рекурсии вопросов нет? А средства для рекурсии есть, просто их придется иначе выражать. Идея проста:

var q =
  db
    .SomeEntity
    .With(db.SomeEntity, (e1, e2) => new {e1, e2})
    .Select(...);


Но это так, мелочь. Куда интереснее другое — рекурсия в SQL в 99% случаев используется для запросов по деревьям. А запросы по деревьям на линке выражаются вообще без рекурсии, потому что линк плоской моделью не ограничен. Т.е. на линке в модели дерево можно описать сразу деревом, а рекурсивные запросы пусть строит провайдер.

G>>>3) MERGE-оператор

НС>>Тоже не проблема.
G>Что значит "не проблема" ?

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

G>Увы в linq таких средств нет


Ты query comprehension с linq не путаешь? В QC и DML нет, а в linq провайдерах оно таки есть.

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

G>То что ты не видишь не значит что их нет.

Ну так давай, рассказывай. А то тот же PIVOT/UNPIVOT, который легко описывается extension методом явно на такое не тянет.

НС>>Эрик? Ссылку можно? А то я немножко на эту тему с ним общался, и ничего подобного не услышал.

G>Это очень давно было, сейчас не найду даже.

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

НС>>Я, кажется, вполне понятно написал. Любая ОРМ, если попытаться от нее абстрагироваться, приведет к leaky abstraction. Без вариантов. Что тебе в этом утверждении непонятно?

G>ты отвечаешь не на то, что я писал.

Извини, но я вообще то и не тебе отвечал по поводу абстракций.
Re[16]: Entity Framework за! и против!
От: Vladek Россия Github
Дата: 18.08.14 21:40
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Это не является ответом на вопрос зачем он нужен. Ты можешь миллион классов придумать, со своими функциями, но это не оправдывает их существования.

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

Скрыть механизм хранения данных от других слоёв приложения. Репозиторий оперирует коллекциями объектов, описывающих предметную область программы. Его контракт свободен от деталей того, какая технология используется внутри него. Это позволяет писать простой код как внутри репозитория, так и снаружи его. Простой код означает, что я быстрее закончу свою работу сейчас и быстрее внесу изменения потом. Простой код — это свободное время, которое я трачу в собственное удовольствие и не думаю о неработающем коде или хитроумном баге.

G>И как это онсоится к репозитарию?

G>"Здесь и сейчас" можно добиться, написав Linq прямо в контроллере. А "легко поддаваться изменениям и оставаться полезным" можно добиться сделав комбинаторы, примерно вот так: http://gandjustas.blogspot.ru/2010/05/iqueryable-generics.html?&amp;tpwf_mode=main
G>А какая польза от репозитория?

IEnumerable<EntityDetails> visibleEntities = repo.GetEntities(new EntityFetch { Visible = true });


И простая читабельная реализация метода GetEntites. Без велосипеда IVisible и костыля к нему FixupVisitor. Хотя бы название метода Fix — не заставило задаться вопросом о целесообразности решения?

V>>Положительные эффекты в разделении зон ответственности кода. Если тебе надо работать с кодом доступа к бд, ты делаешь это в одном месте и не тебе не приходится лазать по всему дереву исходников. В будущем, тебе не придётся долго искать этот код и потом читать половину проекта, чтобы внести изменения и быть уверенным, что ничего не забыто.

G>Весь код работы с БД находится в ORM, а запросы "в одном месте" это фантастика, потому что в каждом контроллере нужны разные запросы. Где-то нужны сортировки, где-то проекции итп. Очень редко запросы дублируются.

Их конечное количество и мы не тратим время на написание универсальных велосипедов.

V>>Этот IEnumerable будет содержать с десяток объектов, уже готовых для отображения пользователю. Любые манипуляции с ним не будут отличаться большими накладными расходами.

G>А где гарантия что десятки?
G>Откуда репозиторий узнает что нужно для отображения пользователю?

DataFetch.PageSize


А про пользователя репозиторий ничего не знает.

G>С такими рассуждениями у тебя вся логика уедет в репозитории и методы репозиториев будут 1-в-1 повторять контроллеры. А проблемы никуда не денутся.


Логика выборки данных для набора конкретных случаев, которые нужны в приложении. И, главное, код будет простой как доска.
Отредактировано 18.08.2014 21:53 Vladek . Предыдущая версия .
Re[7]: Entity Framework за! и против!
От: IT Россия linq2db.com
Дата: 18.08.14 21:43
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>SQL (на примере TSQL) умеет, а Linq нет:

G>1) CTE и рекурсию
G>2) ranking-функции и агрегаты с partition
G>3) MERGE-оператор
G>4) PIVOT\UNPIVOT

Всё это реализуемо. Достаточно придумать удобную сигнатуру методов.
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: Entity Framework за! и против!
От: Vladek Россия Github
Дата: 18.08.14 21:48
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Т.е. ты считаешь, что расширять просто запрос сложнее, чем запрос + руками описанный набор DTO + публичный интерфейс + вызов метода? Сможешь аргументировать?


Не, не смогу. Да просто создавай контекст, там где нужно, и тут же пиши запрос данных. Работает же.

var ctx = new BlogContext();
var posts = ctx.Posts.Where(p => p.Rating == 10);


Абсолютная гибкость.
Re[13]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 18.08.14 21:53
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Да просто создавай контекст, там где нужно, и тут же пиши запрос данных. Работает же.


V>
V>var ctx = new BlogContext();
V>var posts = ctx.Posts.Where(p => p.Rating == 10);
V>

V>Абсолютная гибкость.

Ничего не понял. А как же репозиторий и абстрагируемость?
Re[10]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 22:50
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


НС>>>Чтобы писать код не задумываясь о деталях реализации ORM. Сейчас таких ORM нет.

G>>В первую очередь нужно задумываться о той СУБД, для которой пишешь.

НС>И это тоже. Но, по опыту, работать на разных СУБД все таки намного проще, чем работать на разных ORM. Первое у меня еще получалось, а вот второе — никогда. Даже переезд с blt linq на linq2db на крупных проектах совсем нетривиальная задача.


У меня опыт ровно обратный, не было проблем при переключении между Linq2SQL\EF\NHibernate, большинство запросов не меняются, разница в мелочах, которые отлично прячутся в Extension-методы. А вот когда надо было адаптировать код для SQL Server под SQLCE пришлось потрахацца.

НС>>>Проблема не в транслируемости конструкций, а в том что вполне осмысленные, нормально выглядящие и работающие на linq2objects конструкции на SQL фик переведешь.

G>>Обратное также верно.
НС>Да не особо. Приведенные тобой примере это точно не доказывают.
Ты везде сводишь к тому, что можно написать свои функции и потом их както мапить. Вот только с ranking function ничего хорошего не получается, увы. Особенно если надо сохранить семантику, чтобы аналогичный запрос для linq2objects работал.

НС>>>СТЕ сама по себе линку просто не нужна. А поддердка рекурсии — вопрос конкретных провайдеров, которым просто никто не занимался всерьез.

G>>В linq нет средств для рекурсии.

НС>Т.е. с CTE без рекурсии вопросов нет? А средства для рекурсии есть, просто их придется иначе выражать. Идея проста:

Без рекурсии просто подставляется одно выражение в другое.

НС>Но это так, мелочь. Куда интереснее другое — рекурсия в SQL в 99% случаев используется для запросов по деревьям. А запросы по деревьям на линке выражаются вообще без рекурсии, потому что линк плоской моделью не ограничен. Т.е. на линке в модели дерево можно описать сразу деревом, а рекурсивные запросы пусть строит провайдер.

В линке нет готовых средств для обхода деревьев, все решается через кастомные комбинаторы. Но в SQL семантика рекурсии другая и парой комбинаторов не обойдешься.

G>>>>3) MERGE-оператор

НС>>>Тоже не проблема.
G>>Что значит "не проблема" ?
НС>То и значит что на линке это легко выражается, просто существующие провайдеры такое не умеют.
Ох сомневаюсь что ты сможешь адекватно для Linq написать MERGE чтобы покрыть все возможности оператора.

G>>Увы в linq таких средств нет

НС>Ты query comprehension с linq не путаешь? В QC и DML нет, а в linq провайдерах оно таки есть.
Не путаю, покажи ranking functions в любом провайдере.

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

G>>То что ты не видишь не значит что их нет.
НС>Ну так давай, рассказывай. А то тот же PIVOT/UNPIVOT, который легко описывается extension методом явно на такое не тянет.
Покажи пример.

НС>>>Эрик? Ссылку можно? А то я немножко на эту тему с ним общался, и ничего подобного не услышал.

G>>Это очень давно было, сейчас не найду даже.

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

Ты куда-то в сторону ушел.
Вот что я говорил:
1) Мейер на Haskell создавал систему, которая позволяет код транслировать в SQL (это факт)
2) Мейер эту идею принес в C# (это он говорил, можно попробовать на Channel9 найти это видео)
3) Все пляски с Expression Trees и linq-comprehensions сделаны только для трансляции запросов в SQL. В других языках есть query comprehensions, которые гораздо лаконичнее с такой же выразительной силой.
У тебя есть возражения?

То что не любое дерево выражений можно перевести в SQL я и не спорил. Во-первых внутри ET можно написать любое выражение языка, например создание несериализуемых объектов. Во-вторых linq работает с последовательностям, а SQL с множествами, разница в семантике делает многие linq выражения бессмысленными в SQL. Но оба эих факта никаким образом не связаны с выразительной силой.
Фактически выразительная сила — возможность получить больше результатов выражений, используя меньше кода. Если мы рассматриваем работу с данными, то Linq, увы, в не дотягивает до SQL.
Re[17]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 23:42
Оценка:
Здравствуйте, Vladek, Вы писали:

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


G>>Это не является ответом на вопрос зачем он нужен. Ты можешь миллион классов придумать, со своими функциями, но это не оправдывает их существования.

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

V>Скрыть механизм хранения данных от других слоёв приложения.

Какая от этого польза? Вред мы уже видели, а польза где?

V> Репозиторий оперирует коллекциями объектов, описывающих предметную область программы.

Этими же коллекциями оперирует все остальное приложение. Иначе model binding не будет работать.

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

У тебя получается более сложный код. Потому что потребитель твоего репозитария вынужден формировать класс DataFetch, а внутри репозитария надо этот DataFetch разбирать и собирать Linq запросы. Так еще и статической проверки DataFetch нету.
Не веришь? так попробуй реализовать сценарии, которые я приводил:
1) Показывать посты по дате добавления
2) Показывать посты по количеству оценок за день (самые популярные)
3) Показывать посты по комментов за день (самые обсуждаемые)

Сравни с объемом кода, скоростью разработки и затратами на поддержку без репозитариев

G>>И как это онсоится к репозитарию?

G>>"Здесь и сейчас" можно добиться, написав Linq прямо в контроллере. А "легко поддаваться изменениям и оставаться полезным" можно добиться сделав комбинаторы, примерно вот так: http://gandjustas.blogspot.ru/2010/05/iqueryable-generics.html?&amp;tpwf_mode=main
G>>А какая польза от репозитория?

V>
V>IEnumerable<EntityDetails> visibleEntities = repo.GetEntities(new EntityFetch { Visible = true });
V>

Я могу легко создать десятки интерфейсов-аспектов и комбинаторов к ним, а ты все поместишь в EntityFetch ? Прости, но такое решение будет неюзабельным совершенно. Да и какая гарантия в твоем коде что сущность вообще поддерживает нужный аспект? Никакой. Поэтому получаем больше ошибок и больше кода.

V>И простая читабельная реализация метода GetEntites. Без велосипеда IVisible и костыля к нему FixupVisitor. Хотя бы название метода Fix — не заставило задаться вопросом о целесообразности решения?

Ты комменты прочитай, нет необходимости в этом методе, достаточно написать T:class

V>>>Положительные эффекты в разделении зон ответственности кода. Если тебе надо работать с кодом доступа к бд, ты делаешь это в одном месте и не тебе не приходится лазать по всему дереву исходников. В будущем, тебе не придётся долго искать этот код и потом читать половину проекта, чтобы внести изменения и быть уверенным, что ничего не забыто.

G>>Весь код работы с БД находится в ORM, а запросы "в одном месте" это фантастика, потому что в каждом контроллере нужны разные запросы. Где-то нужны сортировки, где-то проекции итп. Очень редко запросы дублируются.

V>Их конечное количество и мы не тратим время на написание универсальных велосипедов.

Ты выше показываешь как раз "универсальный велосипед" со своим EntityFetch.

V>>>Этот IEnumerable будет содержать с десяток объектов, уже готовых для отображения пользователю. Любые манипуляции с ним не будут отличаться большими накладными расходами.

G>>А где гарантия что десятки?
G>>Откуда репозиторий узнает что нужно для отображения пользователю?

V>
V>DataFetch.PageSize
V>


А проекция? как ты её задавать будешь? А нетривиальные фильтры?

V>А про пользователя репозиторий ничего не знает.

Вот в этом и проблема. Значит запросы будут гораздо менее эффективными от применения репозитариев. А польза в чем?

G>>С такими рассуждениями у тебя вся логика уедет в репозитории и методы репозиториев будут 1-в-1 повторять контроллеры. А проблемы никуда не денутся.

V>Логика выборки данных для набора конкретных случаев, которые нужны в приложении. И, главное, код будет простой как доска.
Так покажи пример. Ты пока что показываешь только усложнения.

Я вообще не понимаю где будет упрощение, если у тебя внутри репозитариев такой же Linq, но параметры ты передаешь через дополнительный (!) класс EntityFetch, с которым ошибиться на порядок проще. Кода больше, ошибок больше, где "простой как доска"?
Re[8]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 18.08.14 23:44
Оценка:
Здравствуйте, IT, Вы писали:

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


G>>SQL (на примере TSQL) умеет, а Linq нет:

G>>1) CTE и рекурсию
G>>2) ranking-функции и агрегаты с partition
G>>3) MERGE-оператор
G>>4) PIVOT\UNPIVOT

IT>Всё это реализуемо. Достаточно придумать удобную сигнатуру методов.


Теперь ждем ranking\agregation функции с partition в linq2db?
Re[9]: Entity Framework за! и против!
От: IT Россия linq2db.com
Дата: 18.08.14 23:53
Оценка:
Здравствуйте, gandjustas, Вы писали:

IT>>Всё это реализуемо. Достаточно придумать удобную сигнатуру методов.

G>Теперь ждем ranking\agregation функции с partition в linq2db?

Как выглядеть будет уже придумал?
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.08.14 00:47
Оценка:
Здравствуйте, IT, Вы писали:

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


IT>>>Всё это реализуемо. Достаточно придумать удобную сигнатуру методов.

G>>Теперь ждем ranking\agregation функции с partition в linq2db?

IT>Как выглядеть будет уже придумал?


не-а, там сложности:
1) в order by надо как-то выражение сортировки генерировать, а в linq для этого только OrderBy\ThenBy, которые требуют IQueryable<T> на входе, а тип T будет зависть от джоинов.
2) надо как-то обыграть ROWS clause
Re[11]: Entity Framework за! и против!
От: IT Россия linq2db.com
Дата: 19.08.14 00:57
Оценка: :)
Здравствуйте, gandjustas, Вы писали:

G>не-а, там сложности:

G>1) в order by надо как-то выражение сортировки генерировать, а в linq для этого только OrderBy\ThenBy, которые требуют IQueryable<T> на входе, а тип T будет зависть от джоинов.

Это вообще не вопрос. В некоторых местах такое уже делается.

G>2) надо как-то обыграть ROWS clause


Думай
Если нам не помогут, то мы тоже никого не пощадим.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.