Entity Framework Include () не работает - PullRequest
44 голосов
/ 18 декабря 2010

У меня есть следующий запрос EF:

TestEntities db = new TestEntities();
var questions = from q in db.Questions.Include("QuestionType")
                from sq in db.SurveyQuestions
                where sq.Survey == surveyTypeID
                orderby sq.Order
                select q;

foreach( var question in questions ) {
    // ERROR: Null Reference Exception
    Console.WriteLine("Question Type: " + question.QuestionType.Description);
}

При получении доступа к свойству QuestionType я получаю исключение нулевой ссылки. Я использую Include ("QuestionType"), но он не работает. Что я делаю не так?

Редактировать : Не выдается исключение нулевой ссылки, когда у меня включена отложенная загрузка.

Редактировать : Включить (), кажется, работает, когда я делаю следующее:

var questions = db.Questions.Include("QuestionType").Select(q => q);

Когда я использую предикат для отдельной сущности, кажется, что Включить не удается. Разве это не разрешено при использовании Включить? Как насчет моего запроса вызывает эту вещь не работает?

Ответы [ 5 ]

55 голосов
/ 18 декабря 2010

Проблема может быть связана с подзапросом в вашем выражении Linq.Подвыборы, группировка и проекции могут привести к тому, что энергичная загрузка с Include завершится сбоем молча, как упоминалось здесь и более подробно объяснено здесь (см. Ответы Диего Веги где-то в серединенить).

Хотя я не вижу, чтобы вы нарушали какое-либо из правил, которым следует следовать при использовании Include, как описано в этих сообщениях, вы можете попытаться изменить запрос в соответствии с рекомендацией:

var questions = from q in db.Questions
                from sq in db.SurveyQuestions
                where sq.Survey == surveyTypeID
                orderby sq.Order
                select q;

var questionsWithInclude = ((ObjectQuery)questions).Include("QuestionType");

foreach( var question in questionsWithInclude ) {
    Console.WriteLine("Question Type: " + question.QuestionType.Description);
}

(Или используйте метод расширения, упомянутый в сообщениях.)

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

24 голосов
/ 13 апреля 2013

Добавьте «System.Data.Entity», и вы сможете позвонить Включить на IQueryable:

var questions = from q in db.Questions
                from sq in db.SurveyQuestions
                where sq.Survey == surveyTypeID
                orderby sq.Order
                select q;

questions = questions.Include("QuestionType");

см .: Как я могу преобразовать DBQuery в ObjectQuery ?

5 голосов
/ 18 апреля 2015

Я столкнулся с этой проблемой: Include(e => e.NavigationProperty) не работает, но решение отличалось от описанного выше.

Проблемный код был следующим:

    UserTopic existingUserTopic = _context.UserTopics
            .Include(ut => ut.Topic)
            .FirstOrDefault(t => t.UserId == currentUserId && t.TopicId == topicId);

        if (existingUserTopic != null)
        {
            var entry = _context.Entry(existingUserTopic);
            entry.State = EntityState.Deleted;

            if (existingUserTopic.Topic.UserCreated) 
            {
                var topicEntry = _context.Entry(existingUserTopic.Topic);
                entry.State = EntityState.Deleted;
            }

            await _context.SaveChangesAsync();
        }

Таким образом, проблема заключалась в порядке кода.Entity Framework, по-видимому, обнуляет свойства навигации в памяти, как только объект помечается как EntityState.Deleted.Таким образом, чтобы получить доступ к existingUserTopic.Topic в моем коде, я должен сделать это, прежде чем пометить existingUserTopic удалено.

0 голосов
/ 30 марта 2019

Поскольку этот вопрос является лучшим результатом поиска для "Entity Framework Включить не работает", я просто упомяну пару других возможностей, хотя ни одна из них не имеет отношения к исходному сообщению @ Dismissile.

Чувствительность к регистру

SQL Server (и, возможно, другие платформы баз данных) часто работают без учета регистра.Таким образом, если у вас есть значение первичного ключа ABC1, база данных примет ABC1, abc1, AbC1 и т. Д. В качестве допустимых значений внешнего ключа.Тем не менее, сравнения строк .Net по умолчанию чувствительны к регистру, поэтому даже если ваш .Include генерирует дополнительный SQL для извлечения дополнительных значений в EF, он может не заполнить дочерние объекты, если в ключах есть регистр.Это обсуждается немного глубже в этом ТАК вопрос с парой хороших ссылок.Использование чувствительной к регистру сортировки для столбцов первичного ключа и внешнего ключа может снизить риск этой причины сбоя .Include.

Пробелы в конце

Это одна из причиня потерял день своей жизни, пытаясь понять, почему мой .Include не работал.SQL Server (и, возможно, другие платформы баз данных) часто игнорируют конечные пробелы при сравнении строк.Таким образом, если у вас есть значение первичного ключа (не включая кавычки) «ABC» (один конечный пробел), база данных примет «ABC» (один пробел), «ABC» (без пробела), «ABC» (2 пробела)) и т. д. в качестве допустимых значений внешнего ключа.Однако при сравнении строк .Net не игнорируются конечные пробелы, поэтому даже если ваш .Include генерирует дополнительный SQL для извлечения дополнительных значений в EF, он может не заполнить дочерние объекты, если в ключах есть различия в конечных пробелах.Поведение SQL Server описано на этой странице MS Support .Я не разработал хорошую стратегию предотвращения такого рода сбоев. Включите, кроме тщательного управления данными, то есть не позволяйте пользователям вводить значения внешнего ключа - используйте выпадающий список или неукоснительно вводите пользовательский ввод.

0 голосов
/ 10 апреля 2018

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

Просто добавьте нужные свойства навигации в конечный результат как «фиктивные» свойства.

(Это работает с прокси отслеживания изменений. Я не проверял его в других ситуациях. Кроме того, не указывайте ".AsNoTracking ()")

   var results = context.Categories.Where(...)
      .GroupJoin(
         context.Books.Where(...),
         cat => cat.Id,
         book => book.CategoryId, 
         (cat, books) => new 
         {
             Category = cat,
             Books = books.ToList()
             Dummy_Authors = books.Select(b => b.Author).ToList() // dummy property
         });

Теперь, если вы делаете что-то подобное,база данных больше не будет запрашиваться.

var cat1 = results.First(); // query executed here
var authorName = cat1.Books.First().Author.Name; // already loaded
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...