Comments 33
В результате мы получим содержимое заказа на текущий момент, а не на момент загрузки самого заказа из базы.Расшифруйте эту фразу подробнее, пожалуйста.
При этом подобные ошибки не так то просто отловить на этапе разработки/ревью и подобный код может выстрелить уже в боевой среде.У меня в привычке всегда использовать SQL Profiler и тогда не приходится ломать голову над правильным составлением linq запросов, сразу видно если что то нужно поправить.
оставить lazy loading включенным но строго следить за тем что бы все навигационные свойства не были виртуальнымиКак тогда будет работать lazy loading?
Вопрос, сколько запросов будет отправлено в базу? Правильно, 3.Непонятно: а как правильно написать запрос, чтобы он не ухудшал производительность? Может на таких маленьких примерах Lazy Loading и не нужен, а что если нужно загрузить 100-400 тыс. записей в какой-нибудь combobox или auto-complete, и чтобы ничего не тормозило, что тогда делать? Есть реальный пример?
1) .Take(n).Skip(m); — то есть пейджинг.
2) .Select(x=> {x.Name, un = x.User.Name}).ToList().Select(x=>x.Name+" "+un);
синтаксис не помню, с головы привел, смысл в том что сначала тянем из базы массово нужную проекцию полей, а потом делаем конкатенацию строк.
если нужно загрузить 100-400 тыс. записейтогда Lazy Loading точно не нужен!
Но это не значит что нужно убрать virtual у свойств, просто используйте Select() и явную загрузку данных (ToList(), ToArray()...).
А уже после явной загрузки данных, делайте в памяти что хотите.
Чтобы ничего не тормозило — надо загружать нужные данные заранее:
var trades = context.Trades
.Where(x => tradeIds.Contains(x.Id))
.Include(x => x.Buyer)
.Include(x => x.Seller);
foreach(var t in trades)
без ToList(), то будут множественные запросы к таблице Trades, которые будут тормозить систему.И в чем же вы видите принципиальную разницу между foreach(var t in trades)
и вызовом ToList()
?
Для справки: реализацию ToList() можно посмотреть на referencesource. И используемый конструктор можно найти там же.
Есть одна очень неприятная особенность EF, при наличии нескольких инклюдов он очень долго генерирует запрос (именно текст запроса). Теоретически должен их кэшировать, но практически кэш очень хрупкий. Пришлось отказаться от инклюдов и жить с lazy, это оказалось в разы быстрее.
Это что же за инклюды у вас? И сколько это получилось — "несколько"?
Обычные 4-6 инклюдов, какой-то системы в этом я не нашел, но поведение зависит от числа инклюдов. Причем генерация может занимать до минуты времени. Вот типичный пострадавший: https://stackoverflow.com/questions/686554/why-is-entity-framework-taking-30-seconds-to-load-records-when-the-generated-que
Не так просто использовать compiled query и это не решит проблему с тормозами, которые первый раз будут все равно.
Представим что в промежутке между загрузкой заказа из базы и обращением к свойству OrderLines содержимое заказа было изменено. В результате мы получим содержимое заказа на текущий момент, а не на момент загрузки самого заказа из базы.Все таки неплохо было бы эти два предложения переписать/уточнить.
Представим что в промежутке между загрузкой заказа из базы и обращением к свойству OrderLines содержимое заказа было изменено в базе, в другой транзакции.
В результате мы получим содержимое заказа на текущий момент (что значит получим, заказ был на момент первого (и единственного) считывания, почему мы получим другой результат?), а не на момент загрузки самого заказа из базы. (Почему это вдруг?)
Если нет транзакции, а был изменен OrderLines, то получим несогласованные данные между Order и OrderLines.
В общем эти два предложения надо раскрыть подробнее.
При использовании lazy loading наши POCO объекты перестают быть POCO
Мне кажется, что использование entity только в «рамках» созданного контекста — это первое, чему учит любой туториал по EF. И за пределы слоя доступа к бд (обычно это отдельный проект?) эти объекты никогда не выходят, а мапятся на POCO.
Вопрос, сколько запросов будет отправлено в базу? Правильно, 3.
Опять же, оператор «Include» в любом туториале в разделе о lazy loading'е всегда упоминается. Подобные ошибки — это незнание инструмента, а не недостаток EF.
Индикатором, того, что EF выполняет запросы по Lazy Loading как правило является @EntityKeyValue1.
Во первых можно сделать «eager loading»: как сказал уважаемый mayorovp добавить INCLUDE
Во вторых можно управлять на уровне контекста: Context.Configuration.LazyLoadingEnabled = false;
Вот тут объясняется про Lazy Loading и как с этим можно бороться.
Lazy Loading в Entity Framework