たとえば、次の 2 つのエンティティがあるとします。
public class Customer
{
public int Id { get; set; }
public int SalesLevel { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
public class Order
{
public int Id { get; set; }
public DateTime DueDate { get; set; }
public string ShippingRemark { get; set; }
public int? CustomerId { get; set; }
public Customer Customer { get; set; }
}
Customer
オプションの(nullable) 参照です (Order
システムが「匿名」注文をサポートしている可能性があります) 。
ここで、注文に顧客がいる場合、注文のいくつかのプロパティを顧客のいくつかのプロパティを含むビュー モデルに投影したいと考えています。私は2つのビューモデルクラスを持っています:
public class CustomerViewModel
{
public int SalesLevel { get; set; }
public string Name { get; set; }
}
public class OrderViewModel
{
public string ShippingRemark { get; set; }
public CustomerViewModel CustomerViewModel { get; set; }
}
Customer
が必須のナビゲーション プロパティである場合Order
、次のプロジェクションを使用できCustomer
ますOrder
。
OrderViewModel viewModel = context.Orders
.Where(o => o.Id == someOrderId)
.Select(o => new OrderViewModel
{
ShippingRemark = o.ShippingRemark,
CustomerViewModel = new CustomerViewModel
{
SalesLevel = o.Customer.SalesLevel,
Name = o.Customer.Name
}
})
.SingleOrDefault();
ただし、Customer
がオプションであり、ID を持つ注文にsomeOrderId
顧客がいない場合、これは機能しません。
EF は、具体化された値が であり、null 許容ではないプロパティに格納できないと不平を言っ
o.Customer.SalesLevel
ていNULL
ます。それは驚くべきことではなく、型を作成することで問題を解決できます(または、通常はすべてのプロパティを null 可能にします) 。int
CustomerViewModel.SalesLevel
CustomerViewModel.SalesLevel
int?
しかし、実際には、注文に顧客がいない場合のように
OrderViewModel.CustomerViewModel
具体化することをお勧めしnull
ます。
これを達成するために、私は次のことを試しました:
OrderViewModel viewModel = context.Orders
.Where(o => o.Id == someOrderId)
.Select(o => new OrderViewModel
{
ShippingRemark = o.ShippingRemark,
CustomerViewModel = (o.Customer != null)
? new CustomerViewModel
{
SalesLevel = o.Customer.SalesLevel,
Name = o.Customer.Name
}
: null
})
.SingleOrDefault();
しかし、これは悪名高い LINQ to Entities 例外をスローします。
タイプ 'CustomerViewModel' の定数値を作成できません。このコンテキストでは、プリミティブ型 (たとえば、''Int32'、'String' および 'Guid'') のみがサポートされます。
それは許されない: null
「定数値」だと思います。CustomerViewModel
割り当てnull
が許可されていないように見えるので、 にマーカー プロパティを導入しようとしましたCustomerViewModel
。
public class CustomerViewModel
{
public bool IsNull { get; set; }
//...
}
そして、投影:
OrderViewModel viewModel = context.Orders
.Where(o => o.Id == someOrderId)
.Select(o => new OrderViewModel
{
ShippingRemark = o.ShippingRemark,
CustomerViewModel = (o.Customer != null)
? new CustomerViewModel
{
IsNull = false,
SalesLevel = o.Customer.SalesLevel,
Name = o.Customer.Name
}
: new CustomerViewModel
{
IsNull = true
}
})
.SingleOrDefault();
これも機能せず、例外がスローされます。
タイプ 'CustomerViewModel' は、単一の LINQ to Entities クエリ内の構造的に互換性のない 2 つの初期化に表示されます。型は、同じクエリの 2 つの場所で初期化できますが、同じプロパティが両方の場所で設定され、それらのプロパティが同じ順序で設定されている場合に限ります。
例外は、問題を解決する方法を十分に明確にしています。
OrderViewModel viewModel = context.Orders
.Where(o => o.Id == someOrderId)
.Select(o => new OrderViewModel
{
ShippingRemark = o.ShippingRemark,
CustomerViewModel = (o.Customer != null)
? new CustomerViewModel
{
IsNull = false,
SalesLevel = o.Customer.SalesLevel,
Name = o.Customer.Name
}
: new CustomerViewModel
{
IsNull = true,
SalesLevel = 0, // Dummy value
Name = null
}
})
.SingleOrDefault();
null
これは機能しますが、すべてのプロパティをダミー値または明示的に埋めることはあまり良い回避策ではありません。
質問:
CustomerViewModel
nullableのすべてのプロパティを作成する以外に、最後のコード スニペットが唯一の回避策ですか?null
投影でオプションの参照を具体化することは単に不可能ですか?この状況に対処するための別のアイデアはありますか?
(この動作はバージョン固有ではないと思うため、この質問には一般的なエンティティ フレームワークタグのみを設定していますが、よくわかりません。上記のコード スニペットを EF 4.2/ DbContext
/Code-First でテストしました。編集: 2タグが追加されました。)