消除实体中的冗余NULL检查

时间:2015-02-13 17:12:33

标签: c# entity-framework linq-to-entities entity-framework-6

List<OfferDTO> offers = dbContext.Offer.Where(x => x.IsDeleted)
    .OrderBy(i => i.OfferID)
    .Skip(start).Take((length))
    .Select(y => new OfferDTO
    {
        OfferStageValue = y.OfferStage.Value ?? null,
        PropertyAddressLine1 = (y.PropertyAuction.Property != null && y.PropertyAuction.Property.Address != null) ? y.PropertyAuction.Property.Address.AddressLine1 : string.Empty,
        PropertyAddressLine2 = (y.PropertyAuction.Property != null && y.PropertyAuction.Property.Address != null) ? y.PropertyAuction.Property.Address.AddressLine2 : string.Empty,
        PropertyCity = (y.PropertyAuction.Property != null && y.PropertyAuction.Property.Address != null) ? y.PropertyAuction.Property.Address.City : string.Empty,
        PropertyZip = (y.PropertyAuction.Property != null && y.PropertyAuction.Property.Address != null) ? y.PropertyAuction.Property.Address.PostalCode : string.Empty,            
    })
    .ToList();

在上面的例子中,我使用select语句直接转换为对象。

在新对象中使用它们的值之前,需要检查某些属性的null值。

但是,如您所见,不同的属性会一遍又一遍地检查null的相同值。具体来说,你看:

(y.PropertyAuction.Property != null && y.PropertyAuction.Property.Address != null)

连续几次检查。

在随后的SQL中,您看到查询每次都在检查null

CASE WHEN (([Extent12].[PropertyID] IS NOT NULL) AND ([Extent13].[AddressID] IS NOT NULL)) THEN [Extent14].[AddressLine1] ELSE @p__linq__1 END AS [C5], 
CASE WHEN (([Extent12].[PropertyID] IS NOT NULL) AND ([Extent15].[AddressID] IS NOT NULL)) THEN [Extent16].[AddressLine2] ELSE @p__linq__2 END AS [C6], 
CASE WHEN (([Extent12].[PropertyID] IS NOT NULL) AND ([Extent17].[AddressID] IS NOT NULL)) THEN [Extent18].[City] ELSE @p__linq__3 END AS [C7]

有没有办法检查一次并将其结束,或者这是安全使用这些值的最佳方法吗?

注意

y是基表

PropertyAuctionProperty,和 Address也是所有单独的表,可能不包含数据。

1 个答案:

答案 0 :(得分:1)

通过切换到Query语法并使用let关键字,您可以在LINQ本身中获得更多优雅,但我认为您将发现您生成的SQL(必须)非常相似:

var offers = (from o in dbContext.Offers
              where o.IsDeleted
              let p = o.PropertyAuction.Property
              let a = p != null ? p.Address : null
              orderby o.OfferID
              select new OfferDTO
    {
        OfferStageValue = o.OfferStage.Value,
        PropertyAddressLine1 = a != null ? a.AddressLine1 : string.Empty,
        PropertyAddressLine2 = a != null ? a.AddressLine2 : string.Empty,
        PropertyCity = a != null ? a.City : string.Empty,
        PropertyZip = a != null ? a.PostalCode : string.Empty,
    })
    .Skip(start).Take(length)
    .ToList();

修改

刚才有机会将完整模型放入编译器并检查SQL - 正如预期的那样,生成的SQL与从原始查询生成的SQL相同; (即,即使提取到LINQ中的单个检查中,生成的SQL也会将这些检查内联四次,从而生成相同的SQL代码)。

如果您的主要目标是更清晰的LINQ代码,那么至少这个答案可以实现。