我需要将EF中的一些POCO实体投影到其缩小的视图模型表示中,以传递给序列化器。在这种情况下的实体是“装运”和“请购单”,并且具有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时出现异常。我如上所述添加了一个空检查,现在得到以下异常。


  无法创建类型为“ Api.ViewModels.Shipment”的常量值。
  仅支持基本类型(例如Int32,String和Guid)
  在这种情况下。


这让我感到很奇怪,因为在添加空检查之前,很高兴创建嵌套的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
                    })


这有效地将所需的“货件”属性展平为单个DTO。如果设置Description属性时,如果任何记录的Shipment为null,我都希望得到一个NullReferenceExcetion。但是这不会发生。 LINQ似乎抑制了该异常,并且ShipmentDescription通过null来传递。它为我省去了对每个嵌套属性的Shipment进行内联null检查的麻烦。不幸的是,当我创建一个不展平的嵌套对象时,这似乎并没有扩展到同样的事情。

最佳答案

您可以将ViewModels.Shipment对象合并到ViewModels.Requisition中,而无需进行null检查,如果Shipment类中的所有属性都可以为空。但是,这有点麻烦,因为现在Shipment对象仅在没有装运的情况下使用空值创建。

您也可以解决这个问题:选择其中包含Shipment集合的Requisitions模型。如果它不会使您的应用程序的其余部分过于混乱,则值得尝试。

10-08 14:02