Pull to refresh

Comments 23

Интересная фича, спасибо за наводку. Не думаю, что ее бы хватило для поддержки `CONTAINS` как минимум из-за того, что `DefaultQuerySqlGenerator` не достаточно универсален и проблема с `= 1` никуда бы не ушла (#9143). Но надо обязательно попробовать этот функционал.
Спасибо за статью, ее очень не хватало. К слову, еще один большой баг EF Core в том, что он выполняет запросы при сборке выражения не ожидания вызовов ToList, ToListAsync и т.д.

Эта возможность есть и в Ef 6 platform кстати.

Плюс к вопросу. Никогда не замечал такого поведения. На 2.0 точно.

Например, сборка выражения по условиям. Мы создаем IQueryable, сортируем его, добавляем условия, соединения и так далее. Затем выполняем запрос, вызывая ToList (и другие известные методы, для трансляции и выполнения SQL-запроса на сервере).

Так вот, помежуточные IQueryable выполняются до финального вызова ToList, причем EF Core это аргументирует в логах тем, что не может транслировать «некоторые выражения» и он вынужден выполнить запрос немедленно и далее уже работать с коллекцией в памяти.

Копание пока ничего не дало, есть старая закрытая issue github.com/aspnet/EntityFrameworkCore/issues/7096

Аналогично для Skip, Take. К примеру, warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Skip(__p_3)' could not be translated and will be evaluated locally.
Да, очень бесит это «улучшение». Если EF6 не может что-то трансировать, то кидает исключение, что мне и надо. Это значит я написал кривой запрос и его надо пофиксать или переделать логику и явно написать `foreach`. EFC молча проглатывает все и исполняет локально. Нет, спасибо, не надо мне такой услуги.
Я видел что такие финты EF Core проделывает с группировкой. Записи вполне могут прогруппироваться на клиенте. Я бы очень внимательно следил за SQL которые в конце концов генерятся.

Можно же:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(...)
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}

Тоже натыкался на такое поведение. Решил довольно просто: OrderBy — должен быть последним в дереве IQueryable. Точнее даже не так — запрос собирается до первого встреченного OrderBy, остальное выполняется на клиенте.
Я имею ввиду вот такие случаи:
var list = dbContext.Persons.where(predicate).orderby(order);
if(filter.value.hasvalue)
{
list = list.where(f=>f.someField == filter.value);
}


Пришлось от такого избавиться и переставить сортировку в конце.
var list = dbContext.Persons.where(predicate);
if(filter.value.hasvalue)
{
list = list.where(f=>f.someField == filter.value);
}
list = list.orderby(order);

Да, конечно, вижу изврат на ровнм месте. Действительно уже кучу раз могли придумать поддержку кастомных функций, об кастомных агрегатах и оконных функциях я вообще молчу.
Ну что же, я рад чо у нас в linq2db это занимает ровно один чих:
github.com/linq2db/linq2db/blob/master/Source/LinqToDB/Sql/Sql.cs#L468
Обычные функции что в EF, что в EF Core делаются столь же просто.
Спасибо за статью.
Задумался, как написать поддержку такого метода расширения, как например
db.Goods.DeleteAsync(x => x.Price > 2000).
Всмысле, метода расширения для IQueryable для генерации Delete запроса.

Не уверен, что это возможно. Такая функциональность противоречит идеологии фреймворка. Закрепление изменений происходит во время вызова метода SaveChanges(). EF и EFC хранят граф объектов и следят за изменениями. По накопленным изменениям генерируются UPDATE, INSERT, DELETE. Каким образом DeleteAsync превратится в граф объектов? Вы, конечно, можете написать простую логику:


  1. Загрузить все объекты x.Price > 2000
  2. Удалить их. Но это будет ужасный оверхед.

Вообще, знающие люди говорят, что Bulk Operations и ORM это из разных областей.

Вы путаете change tracking с самим понятием ORM. Легковесные ORM это делают из коробки. Им совсем не обязательно тянуть запись с сервера чтобы ее изменить или удалить. Из-за таких мелких выборок серьезно проседает SQL сервер в высоконагруженых системах.
Для тех кому надо было пачку обьектов удалять или апдейтть или копировать в другую таблицу или… Добро пожаловать в тестеры!
linq2db.EntityFrameworkCore
Вот есть такой проект: www.zzzprojects.com
В частности, entityframework-plus.net
— Delete without loading entities
— Update without loading entities

Я использую это в bulk actions.
Конечно же принципиально быстрее отрабатывает, без подгрузки записей.
Все ок, если принять и иметь в виду тот факт, что такие действия не обновляют загруженные в DbContext объекты.
Наверное я вас не отговорю если скажу, что код этих расширений ужасен и иногда опасен.
Я провел некоторое время с их кодом, разбираясь как они интегрировались. Это печаль. К сожалению они уже закрыли сурцы, придется им дальше платить без оглядки.
Но если, все же, если я смог закласть зерна сомнения, попробуйте нашу итеграцию linq2db.EntityFrameworkCore. К релизу осталось пару дней, но пробовать можно уже.
спасибо за статью! очень нажная для меня информация.
К сожалению, localdb поставляется без лингвистических сервисов и подключить их не представляется возможным.

поясните пожалуйста, что это значит?
Sign up to leave a comment.

Articles