Как стать автором
Обновить

Комментарии 38

У меня тоже возникают подобные мысли, но я не вижу альтернативы. Да можно делать простые специализированые репозитории, но они плохо работают когда нужно сделать какой-то разухабистый фильрт с кучей условий. Не всегда понятно куда пихать всю эту логику. В DAL-е слишком низкоуревнево, в бизнес логике слишком не абстрактно.
НЛО прилетело и опубликовало эту надпись здесь

И как вы сделаете, чтобы одновременно было удобно (т.е. пользователь мог сделать свой фильтр) и не текло, как IQueryable?

НЛО прилетело и опубликовало эту надпись здесь
А зачем пользователю делать свой фильтр?

Пользователь API — программист.


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

НЛО прилетело и опубликовало эту надпись здесь

У вас фильтрация только на равенство. Этого недостаточно. Нужны диапазоны, нужны строковые операции, нужны операции над частями дат (включая запрос "только по будням").

НЛО прилетело и опубликовало эту надпись здесь
Ну и что — все это так сложно сделать?

Не столько сложно, сколько просто много кода. Лайк, очень много кода.


Все равно для пользователя будет только определенный набор опций.

Вот об этом, собственно и речь: когда этого набора будет не хватать, кто и в каких местах системы должен внести изменения?

НЛО прилетело и опубликовало эту надпись здесь
Разработчик.

Разработчик какого слоя системы? У вас как минимум есть DAL и UI.

НЛО прилетело и опубликовало эту надпись здесь
Очевидно, что и там и там

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

НЛО прилетело и опубликовало эту надпись здесь
Я предложил альтернативу — пускай пользоватеь сам пишет SQL

Ну, собственно, заказчик такого и хочет иногда. Только это как раз и есть пример протекшей абстракции.

Я для себя нашел решение в виде повторения синтаксического дерева SQL (даже статья на хабре про это есть "Дерево синтаксиса и альтернатива LINQ при взаимодействии с базами данных SQL"). “Разухабистый” фильтр передается в виде выражения по всем уровням абстракции (сериализация /десериализация в JSON/XML происходит без проблем) в репозиторий, где он легко превращается в SQL текст. Пользуюсь этим подходом уже несколько лет, забыв про все эти IQueryable как про страшный сон. Все наработки выложил в виде библиотеки на github.

Что бы не быть голословным вот скриншот реально работающего фильтра:
Advanced Filter
image

и JSON создаваемый в клиентском приложении, который легко преобразуется в синтаксическое дерево логического выражения и передается в таком виде до репозитория, где и вставляется в нужный запрос.
Заголовок спойлера
{"typeTag":"and","items":[{"typeTag":"oneOfNum","field":"i_lcid","values":[1049]},{"typeTag":"or","items":[{"typeTag":"not","expr":{"typeTag":"containsStr","field":"vch_firstname","value":"admin"}},{"typeTag":"hasAnyInt","field":"i_user_role","values":[11]}]}]}

Причем к запросу можно автоматически добавить подзапрос, добавляющий “вычисляемое” поле если оно есть в фильтре.
Я тоже этого каждый раз опасаюсь, а потом оказывается, что в жизни реально нужно 5-10 специальных методов в 20% репозиториев в проекте.
Иногда надо просто принять что, набор данных на 100 записей из 5-7 полей лучше отфильтровать на слое бизнес-логики, а не пытаться сделать все в БД и получать дырявые абстракции. Но тут конечно, надо быть осторожным. Такие таблицы иногда могут вырасти)

В общем золотой пули нет, и каждый раз надо смотреть на баланс трудозатрат на разработку, тестирование и поддержку «красивого решения» и профита которое оно даст.
Статья без выводов.
Всё плохо, но что делать, куда идти и прочее — отсутствует.

При этом, проблема действительно есть, есть давно, все уже привыкли =)

А вывод простой — не передавать IQueryable между слоями, его надо оставить его на уровне DAL.

Никаких публичных апи с ним всмысле?
А если взять не IQueryable, а например Odata с его ограниченным набором операций — станет лучше?
Но тогда может получиться DAL который принимает целую модель с 100500+ полями и что-то с ними делает.
Идти в сторону GraphQL :)
Так его кто-то должен на бэке реализовать же? и будет ровно то же, кто-то реализовал не всё, падает notsupported условный.

Или я что-то не знаю про GraphQL?
ну да, реализовать то надо, но нету надобностей в IQueryable так как он из под коробки работает с фильтрациями.

Ну а если кто то что то не правильно реализовал, его вина, пусть исправляет. Как то я не знаю такого языка или фреймворка который бы помогал с такого рода проблемами ))
Хм, я может чего не понимаю, то по моему GraphQL никак не решает проблему указанную в статье.
Может автор прокомментирует.
проблема указанная в статье это успользование IQueryable в апи для предоставления доступа к разного рода фильтрациям(во всяком случае я это так понял) что то вроди анти паттерна. А GraphQL решает это тем что там вообще отпадает нужда в использовании IQueryable.

Каким образом интерфейс может нарушать LSP? Реализация — запросто, но интерфейс то как?

Например, когда он отвечает за много всего сразу. Любой кто захочет его реализовать сделает это по другому и очень высока вероятность что это «по другому» может что-то сломать. Именно это и происходит с IQueryable.

В общем случае плохо «отвечать за все сразу», но это никак к LSP не относится.


Вся дискуссия в итоге о том, стоит ли IQueryable светить в «публичном» API. Я соглашусь с тем, что не стоит, но LSP тут ни при чем. LSP ничего не говорит о сложности реализации или вероятности ошибиться во время реализации. Вот скажите — если вместо IQueryable в API будет Expression от этого что-то поменяется? Expression вообще реализовывать не нужно, он дан нам свыше :)


Я могу аргументировать против IQueryable в публичном API, без привлечения Лисков. Так как IQueryable завязан на провайдера, который часто владеет ценным ресурсом вроде подключения к БД, то нужно всегда знать время жизни этого объекта. А если мы его отдаём всем направо и налево, то жди беды.

Где в IQueryable сказано о базе и о времени жизни? Хм, может быть в IQueryProvider? Нет? Что же это — «детали реализации» получается? Может быть, даже существуют провайдеры, работающие со внешним API, а не БД в качестве источника данных? Так это, выходит, что разные реализации провайдеров не взаимозаменяемы? Как же назывался этот принцип?

Span тоже нарушает LSP потому что внутри у него разные менеджеры памяти?

НЛО прилетело и опубликовало эту надпись здесь

Вот с чего обсуждение началось


Каким образом интерфейс может нарушать LSP? Реализация — запросто, но интерфейс то как?

LSP может нарушить конкретная реализация. Интерфейс не может нарушить пред. и пост. условились, он их устанавливает.

НЛО прилетело и опубликовало эту надпись здесь

Если невозможно сделать две взаимозаменяемых (и полезных) реализации интерфейса, то выполнение LSP для этого интерфейса невозможно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации