1. ホーム
  2. c#

EF: where 節に含める [重複] 。

2023-08-22 13:33:49

質問

タイトルが示唆するように、私はincludeと組み合わせてwhere句を行う方法を探しています。

以下は私の状況です。 私は、コードの匂いでいっぱいの大規模なアプリケーションのサポートに責任があります。 あまりに多くのコードを変更すると、いたるところでバグが発生するので、私は最も安全な解決策を探しています。

例えば、BusとPeopleというオブジェクトがあるとします(BusはPeopleのナビゲーションプロップコレクションを持っています)。 私のクエリでは、起きている乗客だけを乗せたすべてのバスを選択する必要があります。これは単純化したダミーの例です。

現在のコードでは

var busses = Context.Busses.Where(b=>b.IsDriving == true);
foreach(var bus in busses)
{
   var passengers = Context.People.Where(p=>p.BusId == bus.Id && p.Awake == true);
   foreach(var person in passengers)
   {
       bus.Passengers.Add(person);
   }
}

このコードの後、Contextは破棄され、呼び出しメソッドの中で、結果のバスエンティティはDTOクラス(Entityの100%コピー)にマッピングされます。

このコードはDBへの複数回の呼び出しを引き起こし、それはダメなので、次の解決策を見つけました。 MSDN ブログ

これは、結果をデバッグするときはうまくいきましたが、エンティティを DTO にマッピングするとき (AutoMapper を使用)、コンテキスト/接続が閉じられたため、オブジェクトをロードできないという例外が発生します。(コンテキストは常に閉じており、これを変更することはできません :( ))

そこで、選択された Passengers がすでにロードされていることを確認する必要があります (ナビゲーション プロパティの IsLoaded も False です)。Passengersコレクションを検査すると、Countも例外を投げますが、Passegersコレクションに「wrapped related entities」というコレクションもあり、そこには私のフィルタリングされたオブジェクトが含まれています。

これらのラップされた関連エンティティを全体のコレクションにロードする方法はありますか? (これはアプリケーション全体で使用されるため、オートマッパーマッピングの設定を変更することはできません)。

Active Passengersを取得する他の方法はありますか?

何かヒントがあれば教えてください。

編集

Gert Arnold氏の回答は、データがeagerlyにロードされていないため、動作しません。 しかし、私はそれを簡素化し、場所を削除すると、それはロードされます。実行SQLは両方のケースですべての乗客を返すので、これは本当に奇妙なことです。したがって、結果をエンティティに戻すときに問題があるに違いありません。

Context.Configuration.LazyLoadingEnabled = false;
var buses = Context.Busses.Where(b => b.IsDriving)
        .Select(b => new 
                     { 
                         b,
                         Passengers = b.Passengers
                     })
        .ToList()
        .Select(x => x.b)
        .ToList();

編集2

苦労の末、Gert Arnold氏の回答はうまくいきました! Gert Arnold が提案したように、レイジーローディングを無効にして、それをオフのままにしておく必要があります。 前の開発者がレイジーローディングを好んだので、これはアプリケーションにいくつかの余分な変更を要求します -_-。

どのように解決するのですか?

現在 EFコア5.0 's フィルタが含まれる メソッドは、含まれるエンティティのフィルタリングをサポートするようになりました。

var busses = _Context.Busses
                .Include(b => b.Passengers
                                       .Where(p => p.Awake))
            .Where(b => b.IsDriving);