我需要将一些 POCO 实体从 EF 投影到它们的缩减视图模型表示中,以便传递给序列化程序。这种情况下的实体是 Shipment 和 Requisition 并且具有 0..1 关系。如果我不传递视图模型,那么它会在尝试序列化 Requisition 和 Shipment 之间的循环引用时抛出堆栈溢出异常。
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 为空,则在尝试访问 r.Shipment.ID 时出现异常。我如上所述添加了一个空检查,现在得到以下异常。
无法创建“Api.ViewModels.Shipment”类型的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。
这让我觉得很奇怪,因为在我添加空检查之前创建嵌套的 ViewModels.Shipment 作为选择的一部分非常高兴,所以它一定与此有关。
我可以在调用堆栈中看到一些 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 为空,我希望得到一个 NullReferenceExcetion。然而这并没有发生。LINQ 似乎抑制了异常,并且 ShipmentDescription 以 null 的形式出现。它节省了我对每个嵌套属性的 Shipment 进行内联是否为空的检查。不幸的是,当创建一个我没有展平的嵌套对象时,这似乎并没有扩展到同样的事情。