Re[5]: Бизнес логика в ХП
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.06.16 12:39
Оценка: 37 (1) +1
Здравствуйте, Gattaka, Вы писали:

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


G>>Выкини NHibernate, возьми EF или linq2db, там нет таких проблем.

G>Вы будете смеятся, но мы до этого выкинули EF. Был болезненный переход на NH... У EF тоже куча недостатков, например он не позволяется получить вам чистые доменные объекты. То есть в классах доменных сущностей у вас присутсвуют ссылки на типы из EF, а это не правильно. Я, например, должен свободно использовать доменную сущность на клиенте не потащив туда ORM... Да и запросы у EF просто жесткач некоторые, NH в этом плане получше, хотя тоже косячит.
Тут надо разобраться в истории:
Команда компилятора выпустила linq2sql чтобы оправдать наличие Expression Trees в C#. Так как парни в команде компилятора очень крутые, то и из библиотека получилась очень крутой. При этом как и весь компилятор — нифига не расширяемой. Планов на долгосрочное развитие linq2sql не было.
Параллельно упоротые чуваки из команды sql server programmability взяли никому не нужный, переусложненный маппер object spaces и натянули на него linq. Получился EF. Он толком ничего не умел, требовал наследоваться от своих классов и имел довольно странный набор возможностей.
К версии .NET 4.0 в linq2sql поправили пару багов, но больше ничего не произошло, EF тоже немного улучшили (ef4), сделали хотя бы внешние включи в сущностях, поправили немного linq провайдер. Но все равно ef4 был говном.

После этого, в 2012 году, ef отдали команде asp.net. ASP.NET команда очень крутая, решает реальные проблемы, а не выдумывает сфероконей. Первым делом они поверх дерьмового EF написали code first и миграции, с этого момента стало вообще возможно использовать EF (ef5).
Потом избавились от EDM и по максимуму выкинули тяжелое наследие object spaces (к сожалению не полностью), получился вполне достойный ORM (ef6). B самое главное выложили все исходники в опенсорс, появилось дофига поезных расширений.
Теперь решили окончательно выкинуть старый EF, оставили только code first api, для провайдера воспользовались либой relinq (которой кстати пользуется и NHibernate). Это называется EF7 или EFCore.

Куча недостатков, о которых ты пишешь — это в EF4. А если нужен маппер баз всякого барахла уже сейчас можно брать EFCore.


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

G>Таблицы User(Id, Name, Property), Network_Node(Id, Name, Property), User_User(User1Id, User2Id), Network_Node(Node1Id, Node2Id), UserOnNode(NodeId, UserId)
G>В нашей базе 70000 узлов по одному пользователю на узле (для простоты). Пользователи связаны все со всеми. Для некоторый (приблизительно половины) узлов был проставлен признак Prorepry — теперь нужно добавить для таких узлов на которых есть зарегестрированные связанные пользователи . Особенно посчитайте размер таблицы User_User, это приятный момент
И какую задачу решить надо?


G>>>>Код на SQL который более лаконичный и лучше читается не имеет никакого отношения к высокой производительности.

G>>>Ну это был второй аргумент: 1. производительность, 2. локаничность и выразительность. Все таки SQL очень мощный он позволяет вам запросить что вам нужно, а не как извлеч данные.
G>>Ок, напиши запрос, удовлетворяющий следующим условиям:
G>>1) Если пользователь админ, то ему показать все записи
G>>2) Если пользователь не админ, то
G>> — показать ему записи, где пользователь = автор
G>> — или автор записи входит в группу друзей текущего пользователя
G>> — и записи не должны быть скрыты
G>>3) Записи должны быть отфильтрованы по категории, которую выбрал пользователь (id категории — параметр запроса, может быть пусто)

G>>При этом запрос должен быть максимально лаконичным и быстрым.

G>Я считаю — прекрасно, практически на естественном языке
G>
G>select r.id, r.name
G>from rows as r
G>where r.IsHidden = false and 
G>      (exists(select * from Administrators a where a.User = r.User) or 
G>       exist(select * from UserFriends uf where uf.User = r.User and r.Friend = @currentUser ))
G>

1) Фильтр по категории забыл
2) Фильтр по автору поста забыл
3) Фильтр по администраторам неверный, должен быть текущий пользователь админом, а не автор

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

Правильный подход — сделать 4 запроса:
1) Для админа без фильра
2) Для админа с фильтром
3) Для обычного пользователя без фильтра
4) Для обычного пользователя с фильтром
Эти 4 запрос будут работать лучше любого одного, который ты напишешь.
И с linq это приведет всего к двум if в логике программы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.