- Entity Framework Include () не работает со сложным запросом
- Редактировать:
- 4 ответа
- Не работает Entity Framework
- Не удает включить миграции в Entity Framework
- Entity Framework Include() не работает
- 4 ответов
- Подводные камни Entity Framework и производительность
- Включенный трекинг изменений, когда это не нужно
- Постоянная перекомпиляция некоторых запросов
- Использование Contains по коллекции в памяти
- Использование Take и Skip
- Большое количество Include в одном запросе
- Вычитка полей только из базовой сущности при использовании Table Per Type маппинга
Entity Framework Include () не работает со сложным запросом
Рассмотрим следующий запрос LINQ:
Это работает, как ожидалось, но item.ItemProp1.NavProp1 имеет значение NULL . Как объясняется здесь, это связано с тем, что запрос фактически изменяется после использования Include() . но вопрос в том, как выйти из этой ситуации?
Редактировать:
Когда я меняю такой запрос, все работает нормально:
Что касается эта статья Я догадываюсь, в чем проблема . но решение, предложенное автором, не работает в моей ситуации (из-за использования анонимного типа в окончательном выборе, а не тип объекта ).
4 ответа
Как вы упомянули, Include эффективен только тогда, когда конечный результат запроса состоит из сущностей, которые должны включать свойства навигации Include — d.
Итак, в этом случае действует Include :
SQL-запрос будет содержать JOIN , и для каждого SampleEntity будет загружен свой NavProp1 .
В этом случае это нет эффекта:
Запрос SQL даже не будет содержать JOIN , EF полностью игнорирует Include .
Если в последнем запросе вы хотите, чтобы SampleEntity содержали свои NavProp1 , вы можете сделать:
Теперь Entity Framework извлекает сущности SampleEntity и NavProp1 из базы данных по отдельности, но склеивает их вместе с помощью процесса, называемого исправлением отношений . Как видите, для этого не требуется Include .
Однако, если Navprop1 — коллекция, вы заметите, что .
. по-прежнему будет выполнять запрос на выборку Navprop1 путем отложенной загрузки. Это почему?
Хотя исправление отношений заполняет свойства Navprop1 , оно не помечает их как загруженные. Это происходит только тогда, когда Include загружает свойства. Итак, теперь у нас есть SampleEntity , у всех есть свои Navprop1 , но вы не можете получить к ним доступ, не запустив отложенную загрузку. Единственное, что вы можете сделать, чтобы предотвратить это, — это
(или предотвращая отложенную загрузку, отключив создание прокси или не сделав Navprop1 виртуальным.)
Теперь вы получите Navprop1 без нового запроса.
Для свойств справочной навигации это не применяется, ленивая загрузка не запускается, когда она включена.
В ядре Entity Framework ситуация в этой области кардинально изменилась. Запрос типа _db.SampleEntity.Include(s => s.NavProp1).Select(s => new < s >) теперь будет включать NavProp1 в конечный результат. EF-core умнее ищет в конечном результате «включаемые» объекты. Следовательно, мы не будем склонны формировать такой запрос, как Select(s => new < s, s.NavProp1 >) , чтобы заполнить свойство навигации. Однако имейте в виду, что если мы используем такой запрос без Include , отложенная загрузка все равно будет запускаться при доступе к s.NavProp1 .
Как вы узнали, что item.ItemProp1.NavProp1 равно нулю. EF использует прокси для загрузки всех необходимых свойств, когда вы пытаетесь получить к нему доступ.
Вы также можете попробовать
Конечно, я предполагаю, что у вас нет проблем с сопоставлением свойств навигации EF.
Если ваша модель определена правильно, она должна работать без проблем.
Я знаю, что это, вероятно, вызовет смех, но не забывайте очевидное, как я только что сделал. Строка в базе данных фактически не имеет ссылки на внешний ключ! Я должен был сначала проверить данные плотины, прежде чем подумать, что EF Include не работает! Grrr. 30 минут моей жизни я не вернусь.
Источник
Не работает Entity Framework
An unhandled exception of type ‘System.InvalidOperationException’ occurred in EntityFramework.dll
Additional information: The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.
В SQL Server Object Explorer такая картина (черные крестики на папках Database)
Помощь в написании контрольных, курсовых и дипломных работ здесь.
В чем разница между Entity Framework и Entity Framework Core?
В чем разница (если она есть) между entity framework и entity framework core?
Не работает Include() в Entity Framework
Подскажите. пожалуйста. В чём может быть причина, что никак к связям не подобраться? Необходим.
Entity Framework, не работает подключение к существующей базе
Здравствуйте! Начал изучать EF по следующим урокам: http://metanit.com/sharp/entityframework/ .
Странно работает метод StartsWith при запросе к БД SQLite c Entity Framework
Всем привет, помогите кто может. Есть проект c# windows form с entity framework code first. После.
OwenGlendower, написал xml в одну строку- не работает все равно. Скиньте мне пожалуста правильный xml, а то я не совсем понял где именно там этот символ
Добавлено через 9 часов 38 минут
Вспомнил некоторые детали. Судя по всему проблемма не в коде, а в самом Entity Framework или SQL сервере. Я до этого создавал приложение на ASP. NET MVC (так же по примеру, используя Entity Framework подход Code First). Все работало нормально, база создавалась, данные загружались.
После этого решил создать консольное на Entity Framework, то что в вопросе.
И теперь не работает ни оно, ни ASP-шное (безконечно грузится).
Я пробовал переустанавливать все: удалял подключение к серверу, переустанавливал Entity Framework через nuGet, полностью удалял и устанавливал заново Visual Studio. Посоветуйте, что можно попробовать еще переустановить, может быть MS SQL Server? Если ничего не поможет останется только переустановить Windows, но не хочется преждевременно идти на такие крайние меры плюс не зная причины проблемма может повториться уже на новой винде.
Источник
Не удает включить миграции в Entity Framework
Использую Entity Framework 6.2.0.
Проект называется «CrlDownloader».При попытке включить миграции консоль VisualStudion 2017 выдает сообщение:
Выполнил рекомендации из вот этого решения и получил:
В менеджере nuget «Microsoft.EntityFrameworkCore, Version=2.1.4.0» не находится — там уже давно более поздняя версия 2.2.2.
Куда копать дальше? Есть ли у кого-то какие-то идеи?
PS:
Данный проект я клонировал из другого проекта и «обрезал» всё лишнее, переименовав из «Test» в «CrlDownloader». Имена вроде бы везде изменил (правил файлы csproj, csproj.user, sln, config). Может быть из-за этого возникает пролема?
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Entity Framework
Здравствуйте, есть проблема с Entity Framework, как источник данных я указал объекты созданные.
Entity Framework and FluentApi
Всем привет. Есть у меня класс модели, описывающий статусы: public class Status < .
Навигационные свойства в Entity Framework
Всем привет! Помогите разобраться с навигационными свойствами в EF. Уже перечитал и msdn и другие.
Сохранение картинки Entity Framework
Пытаюсь сохранить картинку в базу данных. Использую entity fraemwork. using (AgroFirst db =.
Так вы используете EF 6.2 или EF Core 2.2.2?
Это абсолютно разные вещи, EF Core написан полностью с нуля.
Наверное, в первую очередь стоит определиться с библиотекой, которая должна использоваться.
После чего создать класс, наследующийся от DbContext.
использую EF Core 2.2.2, прошу прощения, что ввел в заблуждение.
Тогда не надо использовать команду Enable-Migrations — она в Core не нужна. Используйте сразу Add-Migration .
Хм. странно. Решил проверить может быть у меня что-то не то с самим проектом и создал в том же решении еще один проект для теста. Установил в него EF Core, EntityFramework (без него команад Enable-Migrations не хотела работать), а затем создал класс Context : System.Data.Entity.DbContext . После этого команда Enable-Migrations нашла контекст и выполнилась (хоть и с ошибками)
Неужели у EF Core не реализована возможность создавать миграции?
Добавлено через 36 секунд
А вот вы об этом и написали
Источник
Entity Framework Include() не работает
у меня есть следующий запрос EF:
Я получаю исключение нулевой ссылки при доступе к свойству QuestionType. Я использую Include («QuestionType»), но он, похоже, не работает. Что я делаю не так?
редактировать: он не выдает исключение нулевой ссылки, когда у меня включена ленивая загрузка.
редактировать: Include (), кажется, работает, когда я делаю следующее:
Когда Я предикат на отдельном объекте Include, похоже, терпит неудачу. Это запрещено при использовании Include? Как насчет моего запроса, который заставляет эту вещь не работать?
4 ответов
проблема может быть связана с подзапросом в вашем выражении Linq. Подселекты, группировка и проекции могут вызвать нетерпеливую загрузку с Include потерпеть неудачу молча, как уже упоминалось здесь и объяснил более подробно здесь (см. ответы Диего Веги где-то в середине потока).
хотя я не вижу, что вы нарушаете какие-либо правила при использовании Include как описано в этих сообщениях, вы можете попытаться изменить запрос согласно рекомендации:
(или используйте метод расширения, упомянутый в сообщениях.)
Если я правильно понимаю связанные сообщения, это не обязательно означает, что он будет работать сейчас (вероятно, нет), но вы получите исключение, дающее вам более подробную информацию о проблеме.
Добавить Системы».Данные.Entity » и вы сможете вызвать Include на IQueryable:
я столкнулся с этим вопросом Include(e => e.NavigationProperty) не работает, но решение было разным, чем выше.
проблемный код был следующим образом:
Итак, проблема заключалась в порядке кода. Entity Framework, похоже, аннулирует свойства навигации в памяти, как только сущность помечена как EntityState.Deleted . Итак, чтобы получить доступ existingUserTopic.Topic в моем коде, я должен сделать это до разметки existingUserTopic удалены.
вот как это сделать во всех типах запросов. Вам не нужно использовать «Include». Единственное, что не похоже, что это работает на многие-ко-многим навигационные свойства.
просто добавьте свойства навигации, которые вы хотите, в конечный результат как «фиктивные» свойства.
(это работает с прокси для отслеживания изменений. Я не проверял его в других ситуациях. Также не уточняйте «.AsNoTracking()»)
теперь, если вы сделаете что-то подобное, база данных больше не будет запрашиваться.
Источник
Подводные камни Entity Framework и производительность
При работе с Entity Framework, как и с любым другими ORM, часто возникают вопросы, связанные с его производительностью. Многие разработчики из-за незнания нюансов делают ошибки, приводящие к плохим результатам. Затем, во время анализа проблем и поиска решений, недостаточно разобравшись в вопросе, приходят к выводу, что улучшить ситуацию можно только переходом на другой ORM или отказом от него вообще. Хоть в некоторых ситуациях такое решение может оказаться разумным, зачастую не все так плохо — просто нужно знать нюансы. В этой статье я попытался собрать те подводные камни, с которыми мне чаще всего приходилось сталкиваться на практике.
- Включенный трекинг изменений, когда это не нужно
- Постоянная перекомпиляция некоторых запросов
- Использование Contains по коллекции в памяти
- Использование Take и Skip
- Большое количество Include в одном запросе
- Вычитка полей только из базовой сущности при использовании Table Per Type маппинга
- Дополнительная информация
Включенный трекинг изменений, когда это не нужно
Предположим, в нашем проекте есть такой фрагмент кода, предназначенный для вычитки некоторого списка сущностей и передачи их затем на клиент:
С первого взгляда, никаких проблем нет, но если в конструкторе контекста не скрыто никаких специальных настроек, этот код приведет к лишним затратам вычислительных ресурсов. У каждого запроса есть атрибут MergeOption, указывающий, как загружать прочитанные запросом объекты в контекст. По умолчанию этот атрибут равен AppendOnly, который говорит о том, что сущности, которых еще нет в контексте, должны быть в него добавлены.
Возникает вопрос — а зачем добавлять объекты в контекст, если нет никаких дальнейших действий по их изменению и сохранению? Ответ — незачем, это лишние расходы, причем заметные. Если объекты, вычитанные с помощью Entity Framework контекста, не будут изменены и не будут участвовать в модификациях других объектов, в соответствующем запросе нужно вызывать AsNoTracking() для коллекции:
Эта функция устанавливает атрибут MergeOption в значение NoTracking, тем самым исключая действия по добавлению прочитанных объектов в контекст. Насколько существенен выигрыш, можно увидеть по этой ссылке https://msdn.microsoft.com/en-us/data/hh949853.aspx (пункт 5.2) или здесь — http://blog.staticvoid.co.nz/2012/4/2/entity_framework_and_asnotracking.
Другая потенциальная проблема, связанная с избыточным трекингом изменений, в первую очередь касается сценариев с добавлением и изменением данных. У конфигурации контекста есть свойство AutoDetectChangesEnabled, которое указывает, надо ли автоматически вызывать метод DetectChanges перед выполнением некоторых операций. К таким операциям относятся добавление объекта в контекст, сохранение изменений в базу, поиск объектов через метод Find и т.д. Вызов DetectChanges нужен, в частности, для определения, что именно поменялось/удалилось/добавилось, для обновления связей между объектами и т.д. Более подробно про то, для чего нужен этот метод, можно почитать здесь — http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/.
Предположим достаточно типовой сценарий — добавление множества объектов в базу:
Значение AutoDetectChangesEnabled по умолчанию равно true, что означает, что при добавлении каждого нового объекта PassengerCar, сперва будет вызван DetectChanges, который пройдется по всем объектам в контексте и проверит наличие изменений. Но в данном случае он совершенно не нужен — изменений добавленных сущностей в этом коде нет, они сохраняются в том виде, в котором были добавлены. А затраты на DetectChanges весьма значительны, примеры можно увидеть здесь — http://blog.staticvoid.co.nz/2012/5/7/entityframework_performance_and_autodetectchanges.
Бездумное выключение свойства AutoDetectChangesEnabled может привести к нежелательным последствиям (потеря изменений, исключения из-за нарушения целостности данных), поэтому наиболее простое правило я бы сформулировал так — если ваш код не предполагает дальнейшего изменения добавленных в контекст объектов в пределах той же сессии, то это свойство можно смело отключать. Такая ситуация встречается довольно часто — типовой CRUD API обычно получает объект извне и либо просто его добавляет, либо еще определяет, какие были сделаны изменения с момента вычитки, и соответствующим образом обновляет информацию о состоянии объекта в контексте (например, с помощью GraphDiff, или с использованием self-tracked entities, или любых других похожих решений). Сам объект при этом не изменяется.
Постоянная перекомпиляция некоторых запросов
Начиная с Entity Framework 5, запросы автоматически кешируются после компиляции, что позволяет значительно ускорить их последующие выполнения — текст SQL запроса будет взят из кеша, остается только подставить требуемые значения параметров. Но есть несколько ситуаций, в которых компиляция будет выполняться при каждом выполнении.
Использование Contains по коллекции в памяти
На практике нередко возникает необходимость добавить в запрос условие, аналогичное SQL-оператору IN — проверить, совпадает ли значение свойства с каким-нибудь из элементов коллекции. Например, вот так:
Это выражение в итоге преобразуется в SQL следующего вида:
Получается, что для оператора IN параметры не используются, а вместо этого подставляются сами значения. Такой запрос закешировать не получится, т.к. при использовании коллекции с другим содержимым текст запроса нужно будет перегенерировать. Это, кстати, бьет не только по производительности самого Entity Framework, но и по серверу базы данных, так как для любого нового списка значений в операторе IN сервер должен будет заново построить и закешировать план выполнения.
Если в коллекции, по которой делается Contains не ожидается большого числа элементов (скажем, не больше ста), проблему можно решить динамической генерацией условий, соединенных оператором OR. Это легко сделать, например, с помощью библиотеки LinqKit:
В итоге получаем уже параметризированный запрос:
Несмотря на то, что динамическое построение запроса выглядит дополнительной затратной работой, на практике на него уходит сравнительно немного процессорного времени. В одной из реальных задач построение запроса при каждом вызове занимало больше секунды. А замена Contains на подобное динамическое выражение уменьшило время обработки запросов (кроме первого) до десятков миллисекунд.
Использование Take и Skip
Во многих проектах возникает необходимость реализовать пейджинг для результатов поиска. Очевидным решением для выборки нужной порции записей тут являются функции Take и Skip:
Посмотрим, какой в этом случае будет SQL:
И размер страницы, и величина смещения указаны в запросе константами, а не параметрами. Это, опять же, говорит о том, что текст запроса кешироваться не будет. К счастью, начиная с Entity Framework 6 есть простая возможность обойти эту проблему — использовать лямбда-выражения в функциях Take и Skip:
И результирующий запрос будет содержать параметры вместо констант:
Большое количество Include в одном запросе
Очевидно, самый простой способ прочитать данные из базы вместе с дочерними коллекциями и другими навигационными свойствами — это использовать метод Include(). Независимо от количества Include() в LINQ запросе, по итогу будет сформирован один SQL запрос, который возвращает все указанные данные. Может сложиться впечатление, что в рамках Entity Framework такой подход для вычитки сложных объектов будет наиболее оптимальным в любой ситуации. Но это не совсем так.
Для начала рассмотрим структуру итогового SQL запроса. Например, у нас есть LINQ запрос с двумя Include для коллекций.
Соответствующий SQL будет содержать UNION ALL:
Логично было бы предположить, что Include() просто добавляет еще один JOIN в запрос. Но Entity Framework ведет себя сложнее. Если включаемое навигационное свойство — единичный объект, а не коллекция, то будет просто еще один JOIN. Если коллекция — то под каждую будет сформирован отдельный подзапрос, где родительская таблица соединяется с дочерней, а все такие подзапросы будут объединены в общий UNION ALL. Очевидно, что если нужна только одна дочерняя коллекция, то UNION ALL не будет. Схематически это можно изобразить так:
Сделано это для борьбы с проблемой перемножения результатов. Предположим, у объекта есть три дочерних коллекции по 10 элементов в каждой. Если все три добавить через OUTER JOIN напрямую в «главный» запрос, то в результате будет 10 * 10 * 10 = 1000 записей. Если же пойти путем Entity Framework, и эти три коллекции собирать в один запрос через UNION, то получим 30 записей. Чем больше коллекций и элементов в них, тем выигрыш подхода с UNION очевиднее.
Но проблема в том, что при большой сложности самих сущностей и критериев выборки, построение и оптимизация такого запроса весьма трудоемки для Entity Framework, как и выполнение его на уровне сервера базы данных. Поэтому если результаты профилирования показывают неудовлетворительную производительность запросов, содержащих Include, а с индексами в базе все в порядке — есть смысл задуматься об альтернативных решениях.
Основная идея альтернативных решений — это вычитка каждой коллекции отдельным запросом. Наиболее простой вариант возможен, если объекты при выборке добавляются в контекст, т.е. без использования AsNoTracking():
Получается, что для каждой дочерней коллекции мы вычитываем все объекты, которые имеют отношение к родительским сущностям, попадающим под критерий запроса. После вызова Load() объекты добавляются в контекст. Во время вычитки родительских сущностей Entity Framework найдет все дочерние, находящиеся в контексте, и соответствующим образом добавит на них ссылки.
Основной недостаток здесь — то, что на каждый запрос идет отдельное обращение к серверу базы данных. К счастью, есть способ решить и эту проблему. В библиотеке EntityFramework.Extended есть возможность создавать «будущие» запросы. Основная идея в том, что все запросы, у которых был вызван extension method Future(), будут посланы в одном обращении к серверу, когда у какого-либо из них будет вызван терминальный метод:
По итогу, как и в первом примере, объекты из коллекции results будут содержать корректно заполненные коллекции Children1 и Children2, причем все данные будут получены за одно обращение к серверу.
Использование «будущих» запросов будет полезно в любых ситуациях, где есть необходимость выполнять несколько отдельных запросов.
Вычитка полей только из базовой сущности при использовании Table Per Type маппинга
Представим себе систему, в которой ряд сущностей имеет базовый класс, содержащий их общие характеристики (название, дата создания, владелец, статус и т.д.). Также есть требование реализовать поиск по этим характеристикам и отображение списка результатов. Отображение подразумевает, опять же, использование только базовых характеристик.
С точки зрения гибкости модели под эту задачу хорошо подходит Table Per Type маппинг, где под каждый тип создается отдельная таблица. Например, у нас есть базовый класс Vehicle и наследники — PassengerCar, Truck, Motorcycle. В этом случае в базе будет создано четыре таблицы.
Напишем запрос, который вычитывает результаты поиска по какому-либо критерию. Например, дата добавления не ранее 10 дней назад:
И посмотрим, во что его преобразует Entity Framework:
Получается, что нам нужна только базовая информация, а Entity Framework вычитывает всю, причем достаточно громоздким запросом. На самом деле в данной конкретной ситуации ничего плохого нет — несмотря на то, что мы выбираем объекты из коллекции базовых классов, фреймворк должен соблюдать полиморфное поведение и возвращать объект того типа, которым он был создан.
Основной вопрос здесь — как упростить запрос, чтобы он не читал лишнее? К счастью, начиная с Entity Framework 5 такая возможность есть — это использование проекции. Просто создаем объект другого типа или анонимный, используя для его заполнения только свойств базовой сущности:
И все становится намного проще:
Но есть и неприятные новости – если в базовом классе есть коллекция, и ее нужно вычитывать, проблема остается. Вот пример:
И сгенерированный для него SQL:
Я создавал тикет для Entity Framework на эту тему: https://entityframework.codeplex.com/workitem/2814, но мне вежливо ответили, что в виду большой сложности и опасности все разломать, они это исправлять не будут.
В некоторых случаях, когда размер базы и/или количество объектов-наследников невелики, с этим можно жить. Если подобные запросы начинают ощутимо ухудшать производительность, нужно искать решения. Раз на уровне самого фреймворка проблему предотвратить нельзя, нужен обходной путь. Наиболее простой вариант здесь — дочитывать коллекции отдельными запросами, например:
Универсального рецепта здесь нет, и приведенное выше решение может не дать выигрыша во всех случаях. Например, базовый запрос может оказаться достаточно сложным, и выполнять его по новой для каждой коллекции будет накладно. Попытаться обойти эту проблему можно через получение списка идентификаторов из результатов базового запроса, а потом использование его во всех дальнейших подзапросах. Но если результатов много, выигрыша может и не быть. К тому же, в этом случае следует помнить о том, что было сказано ранее о методе Contains, который явно напрашивается для поиска по идентификаторам.
Общий подход к решению проблемы я бы сформулировал так — если есть возможность не использовать Table Per Type маппинг, лучше его не использовать. В тех случаях, когда без него сложно обойтись, нужно попробовать варианты, описанные выше, и посмотреть, дают ли они выигрыш.
Источник