web-dev-qa-db-ja.com

Entity Framework Include()が機能していません

次の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プロパティにアクセスすると、null参照例外が発生します。 Include( "QuestionType")を使用していますが、機能していないようです。私は何を間違えていますか?

編集:遅延読み込みをオンにしている場合、null参照例外はスローされません。

編集:Include()は、次のことを行うと機能しているようです:

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

別のエンティティを述語すると、インクルードが失敗するようです。 Includeを使用する場合、許可されませんか?私のクエリがこのことを機能させない原因は何ですか?

44
Dismissile

問題は、Linq式のサブクエリに関連している可能性があります。 here で説明されているように、副選択、グループ化、および射影により、Includeの積極的な読み込みがサイレントに失敗することがあります here (Diego Vegaの回答をどこかで参照してください)スレッドの途中で)。

これらの投稿で説明されている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);
}

(または、投稿に記載されている拡張メソッドを使用します。)

リンクされた投稿を正しく理解していれば、必ずしもそれが現在動作する(おそらく動作しない)とは限りませんが、問題の詳細を示す例外が表示されます。

55
Slauma

「System.Data.Entity」を追加すると、IQueryableでIncludeを呼び出すことができます。

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 <T>をObjectQuery <T>に変換するにはどうすればよいですか?

24
Akli

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();
        }

そのため、問題はコードの順序でした。エンティティフレームワークは、エンティティがEntityState.Deletedとしてマークされるとすぐにメモリ内のナビゲーションプロパティを無効にするようです。したがって、コードでexistingUserTopic.Topicにアクセスするには、existingUserTopicを削除済みとしてマークする前にアクセスする必要があります。

5
parliament

この質問は「Entity Framework Include not working」の検索結果の上位であるため、@ Dismissileの元の投稿には関係ないものの、他のいくつかの可能性について言及します。

ケース感度

SQL Server(および場合によっては他のデータベースプラットフォーム)は、大文字と小文字を区別しない方法で動作することがよくあります。したがって、主キー値ABC1がある場合、データベースは有効な外部キー値としてABC1、abc1、AbC1などを受け入れます。ただし、.Net文字列比較ではデフォルトで大文字と小文字が区別されるため、.Includeが追加のSQLを生成して追加の値をEFにプルしている場合でも、キーに大文字と小文字の違いがあると、子オブジェクトの設定に失敗する可能性があります。これについてはもう少し詳しく説明します SO question 良いリンクがいくつかあります。主キーと外部キーの列に大文字と小文字を区別する照合を使用すると、.Includeエラーのこの原因のリスクを減らすことができます。

トレーリングスペース

これは、なぜ.Includeが機能しなかったのかを解明しようとして私の人生の1日を失った原因です。 SQL Server(および場合によっては他のデータベースプラットフォーム)は、文字列比較の末尾のスペースを無視することがよくあります。したがって、主キー値(引用符を含まない) "ABC"(末尾のスペース1つ)がある場合、データベースは "ABC"(スペース1つ)、 "ABC"(スペースなし)、 "ABC"(スペース2つ)を受け入れます。 )など、有効な外部キー値として。ただし、.Net文字列比較は末尾のスペースを無視しないため、.Includeが追加の値をEFにプルするための追加のSQLを生成している場合でも、キーの末尾のスペースに違いがあると、子オブジェクトの設定に失敗する可能性があります。 SQL Serverの動作については、この MSサポート ページで説明しています。慎重なデータ管理以外の障害を含める、つまり、ユーザーに外部キー値の入力を許可しない-ドロップダウンリストを使用する、またはユーザー入力を宗教的に使用するなど、この種のエラーを防ぐための適切な戦略を立てていません。

0
Rhys Jones