Comments 38
Такое количество оверхеда и костылей чтобы не писать примитивный SQL запрос… впечатляет. Мне любопытно, вы таки достигли в этом потолка или готовы съесть ещё кактуса сверх того, чтобы только не изучать синтаксис оператора SELECT ?
Из вашего комента следует, что ВСЕ крупные проекты используют ентитфреймворк. Вы с луны свалились?
Ок, расскажите чего именно я не понимаю из того, что следовало бы.
Ок, расскажите чего именно я не понимаю из того, что следовало бы.
Например, вы не понимаете (или делаете вид, что не понимаете) того, что иметь дело с деревом выражений намного удобнее, чем с SQL-в-строке. Например, если вам надо на лету дописывать критерии (бизнес-фильтрация, "логическое удаление", безопасность).
поддерживаем одно такое приложение, которое судя по профайлеру — один и тот же запрос делает 2-3 раза подряд :( да и вообще данные выбирает, в своей массе одиночными запросами, как будто курсором проходится по таблице, для выбора нескольких подряд записей :(
если мне нужно нетривиальное генерирование SQL, я использую другой язык программирования, который позволяет делать более мощные абстракции, чем паттерн визитор и дерево выражений Linq Expression. Наример, с провайдерами типов или с синтаксическими макросами. И в котором нет нужды в инструментах наподобие EF
… это если у вас есть возможность взять другой язык программирования. У вас она, возможно, есть. У других людей ее может и не быть.
(ну и да, мне, конечно, интересно, что за абстракцию мощнее, чем AST, вы будете использовать)
У других людей ее может и не быть.
В таком случае коль скоро язык и среда не предоставляют других адекватных средств — ado net. Впрочем, я не могу себе представить проект .net, в котором нельзя использовать F#, то есть лично я бы создавал запросы из Quoted Expressions если этого оказалось бы не достаточно.
что за абстракцию мощнее, чем AST, вы будете использовать
Вопрос не верный. AST бываю разные. Сабжеваое — полный отстой. Правильный вопрос — где можно использовать наиболее простой алгоритм и структуры данных для генерации SQL, а так же синтаксис в дереве. Ответ — Clojure.
В таком случае коль скоро язык и среда не предоставляют других адекватных средств — ado net.
Ну вот видите, вам ado.net, а я предпочту иметь хоть какой-нибудь работающий AST вместо строк. Каждому свое.
Впрочем, я не могу себе представить проект .net, в котором нельзя использовать F#
Корпоративный стандарт на C#?
лично я бы создавал запросы из Quoted Expressions
И что, такая большая разница с System.Expressions
?
Вопрос не верный. AST бываю разные.
Паттерн-то один и тот же.
Сабжеваое — полный отстой.
Аргументы (отличные от "мне неудобно") в студию.
хоть какой-нибудь работающий AST
ado net тоже таки работает. Откуда следует, что этот подход чем-то хуже?
Корпоративный стандарт на C#?
Корпоративный стандарт не законы шариата, а менеджмент не упоротые гашишные имамы — обычно идут на встречу, если от ноухау проект технически выигрывает.
И что, такая большая разница с System.Expressions?
Да. Простая декомпозиция произвольного кода, паттернматчинг вместо визитора, синтаксис F# в дереве, никаких проблем с пониманием вызовов функций, не надо использовать рефлексию.
Паттерн-то один и тот же.
это абсолютно ни о чём не говорит
Откуда следует, что этот подход чем-то хуже?
Оттуда, что ручной парсинг SQL для его изменения более хрупок, чем работа с деревом.
обычно идут на встречу, если от ноухау проект технически выигрывает.
Обучать остальных 50+ программистов F# кто будет?
А при чём здесь ручной парсинг SQL?
Как правило острой необходимости обучать всех нет, поскольку бинарная совместимость сборок, общие инструменты, структуры данных и экосистема. Но если надо — обучатся сами, или вон из профессии.
А при чём здесь ручной парсинг SQL?
При описанной выше задаче: "Например, если вам надо на лету дописывать критерии (бизнес-фильтрация, "логическое удаление", безопасность)."
Но если надо — обучатся сами, или вон из профессии.
Бизнес с вами не согласен. По крайней мере, в моем опыте.
Это не ответ. Вопрос остаётся — зачем при для создания SQL запросов ado net для взаимодействия с SQL сервером парсить стороку с SQL запросом только потому, что я не хочу Linq Expressions.
Не всегда есть человек, который способен внятно объяснить менеджменту выгоды от применения F#.
Вопрос остаётся — зачем при для создания SQL запросов ado net для взаимодействия с SQL сервером парсить стороку с SQL запросом только потому, что я не хочу Linq Expressions.
Потому что у вас есть один компонент, который создает запрос в БД по каким-то своим правилам, а потом есть другой, который хочет этот запрос поменять. И если у вас первый компонент будет создавать сразу SQL-строку, второму придется ее парсить.
Нет. У меня есть функция, у которой на входе бизнес требования, на выходе данные. Строка запроса, по которому она получает эти данные, является внутренyей деталью работы этой функции. Эта строка либо кэшируется, либо отдаётся сборщику мусора.
Что касается темы статьи, то мы используем нашу же разработку Mindbox Expressions, в которой есть метод ExpandExpressions, делающий то же самое, только интерфейс чуть поприятнее :-)
Так же есть LINQKit, в котором есть AsExpandable, позволяющий примерно то же самое.
FilterContainsText<TEntity>(entities, getProperty, text)
Сделать это просто, достаточно поменять сигнатуру у метода и внутри собрать новый LambdaExpression:
public IQueryable<TEntity> FilterContainsText<TEntity>(
IQueryable<TEntity> entities,
Expression<Func<TEntity, string>> getProperty, // компилятор C# так умеет
string text)
{
return entities.Where(Expression.Lambda<Func<TEntity, bool>>
(
body: Expression.Call
(
getProperty.Body,
nameof(string.Contains),
Type.EmptyTypes,
Expression.Constant(text)
),
parameters: getProperty.Parameters
));
}
Как пример — есть таблица каких-нибудь студентов, хочется иметь фильтр по ФИО, по группе, по статусу дипломных работ. Причем, поведение фильтров в комбинации зависит от специальности студента. Бизнес-правила могут быть сложные. Вот тут и приходит на помощь динамическая фильтрация.
Мы можем определить несколько выражений, которые соответствуют каждому фильтру по отдельности, потом при помощи ExpressionVisitor и его реализации в PredicateBuilder строить динамически выражение, которое описывает комбинацию этих фильтров. После чего это выражение уже запихивать в тот же Entity Framework, например.
Лично я использую подобную методику на своем проекте, генерируемый SQL-код действительно похож на тот, что я бы написал вручную.
Тем более, что способ использования… не слишком очевиден, попахиает шаманством :)
Я недавно решал в чём-то схожую задачу: делал фильтр для js-грида. В используемом мной гриде был встроенный механизм автофильтров, но работал только на клиентской стороне, а мне очень хотелось не тащить ни клиента лишние данные… Итогом стал универсальный механизм фильтрации на стороне сервера, работающий для любых данных. Со стороны клиента прилетает список фильтров «имя поля/тип фильтра/фильтрующее значение», а коде контроллера получается что-то вроде
IQueryable<T> source = DAL.GetQuery<T>();
IQueryable<T> data = source.ApplyFilter(filters);
Если интересно — могу код выложить и статейку по это набросать.
Использование выражений для фильтрации данных из БД