シリアライザーに渡すために、一部の POCO エンティティを EF からカットダウン ビュー モデル表現に投影する必要があります。この状況のエンティティは、Shipment と Requisition であり、0..1 の関係があります。ビュー モデルを渡さないと、要求と出荷の間の循環参照をシリアル化しようとして、スタック オーバーフロー例外がスローされます。
return db.ShipmentRequisitions
.Include(c => c.Shipment)
.Select(r => new ViewModels.Requisition
{
ID = r.ID,
...
Shipment = r.Shipment != null ? new ViewModels.Shipment
{
ID = r.Shipment.ID,
...
} : null
}).AsQueryable();
Shipment が null の場合、r.Shipment.ID にアクセスしようとすると例外が発生します。上記のように null チェックを追加したところ、次の例外が発生しました。
タイプ「Api.ViewModels.Shipment」の定数値を作成できません。このコンテキストでは、プリミティブ型 (Int32、String、および Guid など) のみがサポートされます。
null チェックを追加する前に、ネストされた ViewModels.Shipment を select の一部として作成できてよかったので、これは奇妙に思えます。
コール スタックに EF が見られるので、純粋な LINQ で試してみるために、単純なオブジェクトだけを使用した簡単なテスト プロジェクトで試してみました。
var user = users.Select(u => new ViewModel.User
{
Id = u.Id,
Profile = u.Profile != null ? new ViewModel.Profile
{
Id = u.Profile.Id
} : null
}).ToList();
驚いたことに、うまくいきました。最初のコード サンプルでは、何が機能しないのかよくわかりません。
アップデート
選択の一部として次のようなことを行う場合、私はそれを発見しました:
.Select(r => new ViewModels.Requisition
{
ID = r.ID,
ShipmentDescription = r.Shipment.Description
})
これにより、必要な Shipment プロパティが単一の DTO に効果的にフラット化されます。ここで、Description プロパティを設定するときに、いずれかのレコードで Shipment が null の場合、NullReferenceExcetion を取得することを期待します。しかし、それは起こりません。LINQ は例外を抑制しているようで、ShipmentDescription は null と同じように渡されます。ネストされたプロパティごとに、Shipment のインライン is null チェックを行う手間が省けます。残念ながら、フラット化していないネストされたオブジェクトを作成する場合、これは同じ種類のものには拡張されないようです。