2

我需要将一些 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 进行内联是否为空的检查。不幸的是,当创建一个我没有展平的嵌套对象时,这似乎并没有扩展到同样的事情。

4

2 回答 2

1

如果类中的所有属性都是可空的,您可以在不检查空值的情况下合并ViewModels.Shipment对象。不过这有点痛苦,因为现在只有在没有发货的情况下才使用空值创建对象。ViewModels.RequisitionShipmentShipment

你也可以把它转过来:选择Shipment其中包含集合的模型Requisitions。如果它不会过多地弄乱应用程序的其余部分,那么值得一试。

于 2012-09-19T23:06:53.970 回答
0

问题是这一行:

.SingleOrDefault(r => r.ID == id);

EF 正在尝试将表达式转换r.ID == id为 SQL,而不是进行管理。

解决方案是简单地将行更改为: .ToEnumerable().SingleOrDefault(r => r.ID == id);

这是有效的,因为只有 IQueryable 被转换为 SQL,而不是 IEnumerable。

于 2012-09-19T15:19:35.007 回答