【问题标题】:Linq query with different behavior in 4.0 compared to 3.5 (let keyword issue?)与 3.5 相比,4.0 中具有不同行为的 Linq 查询(让关键字问题?)
【发布时间】:2011-07-28 02:44:22
【问题描述】:

在此处输入代码`我有几个使用“let”关键字的 Linq 查询。它们在 3.5 中运行良好,但我在 4.0 中看到了一个非常奇怪的行为。

例子:

 var query1 =
            (from xVehicleOption in this.entities.VehicleOptionSet
                let regionPriceAdjustment = (from xOptionRegionPriceAdjustmentLeftOuter in this.entities.OptionRegionPriceAdjustmentSet
                                            where xOptionRegionPriceAdjustmentLeftOuter.VehicleTypeRegionId == this.vehicleTypeRegionId
                                            && xOptionRegionPriceAdjustmentLeftOuter.VehicleId == this.vehicleId
                                            && xOptionRegionPriceAdjustmentLeftOuter.VehicleOptionId == xVehicleOption.VehicleOptionId
                                            select new
                                            {
                                                xOptionRegionPriceAdjustmentLeftOuter,
                                                xOptionRegionPriceAdjustmentLeftOuter.xPriceType
                                            })
                where xVehicleOption.VehicleId == this.vehicleId
                && (xVehicleOption.OptionTypeId == 5 || xVehicleOption.OptionTypeId == 7)
                select new
                {
                    Name = xVehicleOption.DisplayName,
                    VehicleOptionId = xVehicleOption.VehicleOptionId,
                    SortOrder = xVehicleOption.SortOrder,
                    OptionAvailability = xVehicleOption.OptionAvailabilityDisplayName,
                    IsDefaultConfiguration = xVehicleOption.IsDefaultConfiguration,
                    OptionType = xVehicleOption.OptionTypeDisplayName,
                    RegionPriceAdjustment = regionPriceAdjustment
                }).OrderBy(o => o.SortOrder);

这允许枚举 2 个嵌套循环。每个选项一个,一个选项内的每个区域调整一个。

foreach (var bookOption in query)

{
    .......    
    foreach (var regionAdjustment in bookOption.RegionPriceAdjustment)    
    {    
         .......    
    }    
}

4.0 中的问题是生成的 SQL 是一个 SELECT FROM RegionPriceAdjustment 表,没有任何 WHERE 子句(使用 Profiler 跟踪)。这意味着命令超时(无论如何都是错误的,因为查询的其他部分没有任何迹象)。

我试图用 .Include 替换“let”,这适用于启用延迟加载,但它会为每个 PriceType 生成一个动态 sql 语句(有 8 个,因此效率不高)。我试图禁用延迟加载,但这肯定会给我一个错误,因为 PriceType 没有被加载。我尝试使用两个 select 分隔为 into,但我遇到了同样的问题。

顺便说一句,在 4.0 中,我将 POCO 和 EntityFramework DLL 与 DbContext 对象一起使用。我没有尝试过使用 ObjectContext,但这不应该有任何区别,因为 DbContext 环绕在 ObjectContext 周围。

关于它为什么这样做的任何线索?有什么建议吗?

谢谢,伊夫

已编辑:

这是 3.5 的 SQL:

[Project2].[VehicleOptionId] AS [VehicleOptionId],  
[Project2].[DisplayName] AS [DisplayName],  
[Project2].[OptionAvailabilityDisplayName] AS [OptionAvailabilityDisplayName],  
[Project2].[IsDefaultConfiguration] AS [IsDefaultConfiguration],  
[Project2].[SortOrder] AS [SortOrder],  
[Project2].[VehicleOptionId1] AS [VehicleOptionId1],  
[Project2].[CategoryId] AS [CategoryId],  
[Project2].[CategoryId1] AS [CategoryId1],  
[Project2].[DisplayName1] AS [DisplayName1],  
[Project2].[C1] AS [C1],  
[Project2].[C2] AS [C2],  
[Project2].[VehicleOptionId2] AS [VehicleOptionId2],  
[Project2].[VehicleTypeRegionId] AS [VehicleTypeRegionId],  
[Project2].[VehicleId] AS [VehicleId],  
[Project2].[PriceTypeId] AS [PriceTypeId],  
[Project2].[PriceAdjustment] AS [PriceAdjustment],  
[Project2].[ValueTypeId] AS [ValueTypeId],  
[Project2].[PriceTypeId1] AS [PriceTypeId1],  
[Project2].[DisplayName2] AS [DisplayName2] 
FROM ( SELECT  
        [Extent1].[VehicleOptionId] AS [VehicleOptionId],  
        [Extent1].[DisplayName] AS [DisplayName],  
        [Extent1].[OptionAvailabilityDisplayName] AS [OptionAvailabilityDisplayName],  
        [Extent1].[IsDefaultConfiguration] AS [IsDefaultConfiguration],  
        [Extent1].[SortOrder] AS [SortOrder],  
        [Extent2].[VehicleOptionId] AS [VehicleOptionId1],  
        [Extent2].[CategoryId] AS [CategoryId],  
        [Extent3].[CategoryId] AS [CategoryId1],  
        [Extent3].[DisplayName] AS [DisplayName1],  
        1 AS [C1],  
        [Project1].[VehicleOptionId] AS [VehicleOptionId2],  
        [Project1].[VehicleTypeRegionId] AS [VehicleTypeRegionId],  
        [Project1].[VehicleId] AS [VehicleId],  
        [Project1].[PriceTypeId] AS [PriceTypeId],  
        [Project1].[PriceAdjustment] AS [PriceAdjustment],  
        [Project1].[ValueTypeId] AS [ValueTypeId],  
        [Project1].[PriceTypeId1] AS [PriceTypeId1],  
        [Project1].[DisplayName] AS [DisplayName2],  
        [Project1].[C1] AS [C2] 
        FROM    [dbo].[KBB_V3_VehicleOption] AS [Extent1] 
        INNER JOIN [dbo].[KBB_V3_VehicleOptionCategory] AS [Extent2] ON ([Extent1].[VehicleOptionId] = [Extent2].[VehicleOptionId]) OR (([Extent1].[VehicleOptionId] IS NULL) AND ([Extent2].[VehicleOptionId] IS NULL)) 
        INNER JOIN [dbo].[KBB_V3_Category] AS [Extent3] ON ([Extent2].[CategoryId] = [Extent3].[CategoryId]) OR (([Extent2].[CategoryId] IS NULL) AND ([Extent3].[CategoryId] IS NULL)) 
        LEFT OUTER JOIN  (SELECT  
                [Extent4].[VehicleOptionId] AS [VehicleOptionId],  
                [Extent4].[VehicleTypeRegionId] AS [VehicleTypeRegionId],  
                [Extent4].[VehicleId] AS [VehicleId],  
                [Extent4].[PriceTypeId] AS [PriceTypeId],  
                [Extent4].[PriceAdjustment] AS [PriceAdjustment],  
                [Extent4].[ValueTypeId] AS [ValueTypeId],  
                [Extent5].[PriceTypeId] AS [PriceTypeId1],  
                [Extent5].[DisplayName] AS [DisplayName],  
                1 AS [C1] 
                FROM  [dbo].[KBB_V3_OptionRegionPriceAdjustment] AS [Extent4] 
                LEFT OUTER JOIN [dbo].[KBB_V3_PriceType] AS [Extent5] ON [Extent4].[PriceTypeId] = [Extent5].[PriceTypeId] ) AS [Project1] ON ([Project1].[VehicleTypeRegionId] = @p__linq__6) AND ([Project1].[VehicleId] = @p__linq__7) AND ([Project1].[VehicleOptionId] = [Extent1].[VehicleOptionId]) 
        WHERE (4 = [Extent1].[OptionTypeId]) AND ([Extent1].[VehicleId] = @p__linq__9) AND (22 = [Extent3].[CategoryTypeId]) 
)  AS [Project2] 
ORDER BY [Project2].[SortOrder] ASC, [Project2].[VehicleOptionId] ASC, [Project2].[VehicleOptionId1] ASC, [Project2].[CategoryId] ASC, [Project2].[CategoryId1] ASC, [Project2].[C2] ASC',N'@p__linq__6 int,@p__linq__7 int,@p__linq__9 int',@p__linq__6=0,@p__linq__7=261637,@p__linq__9=261637

这是我仅在 4.1 中得到的(使用 POCO):

    SELECT  
[Extent1].[VehicleOptionId] AS [VehicleOptionId],  
[Extent1].[VehicleTypeRegionId] AS [VehicleTypeRegionId],  
[Extent1].[VehicleId] AS [VehicleId],  
[Extent1].[PriceTypeId] AS [PriceTypeId],  
[Extent1].[PriceAdjustment] AS [PriceAdjustment],  
[Extent1].[ValueTypeId] AS [ValueTypeId] 
FROM [dbo].[KBB_V3_OptionRegionPriceAdjustment] AS [Extent1]

如您所见,没有 WHERE 子句,也没有其他 SQL 的踪迹......

【问题讨论】:

    标签: linq-to-entities


    【解决方案1】:

    不过,我找到了一种解决方法。我的新查询如下:

    var query = 
      (from xVehicleOption in this.entities.VehicleOptionSet 
       let regionPriceAdjustment = (from xOptionRegionPriceAdjustmentLeftOuter in xVehicleOption.XOptionRegionPriceAdjustment 
          where xOptionRegionPriceAdjustmentLeftOuter.VehicleTypeRegionId == this.vehicleTypeRegionId 
          //&& xOptionRegionPriceAdjustmentLeftOuter.VehicleId == this.vehicleId 
          //&& xOptionRegionPriceAdjustmentLeftOuter.VehicleOptionId == xVehicleOption.VehicleOptionId 
          select new 
          { 
           xOptionRegionPriceAdjustmentLeftOuter, 
           xOptionRegionPriceAdjustmentLeftOuter.XPriceType 
          }) 
       join xVehicleOptionCategory in this.entities.VehicleOptionCategorySet on xVehicleOption.VehicleOptionId equals xVehicleOptionCategory.VehicleOptionId 
       join xCategory in this.entities.CategorySet on xVehicleOptionCategory.CategoryId equals xCategory.CategoryId 
       where xVehicleOption.VehicleId == this.vehicleId 
       && xVehicleOption.OptionTypeId == 4 
       && xCategory.CategoryTypeId == 22 
       select new 
       { 
       Name = xVehicleOption.DisplayName, 
       VehicleOptionId = xVehicleOption.VehicleOptionId, 
       SortOrder = xVehicleOption.SortOrder, 
       OptionAvailability = xVehicleOption.OptionAvailabilityDisplayName, 
       IsDefaultConfiguration = xVehicleOption.IsDefaultConfiguration, 
       OptionType = xCategory.DisplayName, 
       RegionPriceAdjustment = regionPriceAdjustment 
       }).OrderBy(o => o.SortOrder); 
    

    请注意,在第三行中,我从 xVehicleOption 而不是 this.entities. 查询,因此进行了内部连接。当然,我不需要现在被注释掉的行。我在阅读 Craig Stuntz 的优秀文章时发现了这个解决方案:

    http://blogs.teamb.com/craigstuntz/2010/01/13/38525/

    当然,根据 Craig 的说法,我的查询可以更加简化,但出于易于理解的原因,我想保留大部分内容。

    这仍然不能解释为什么原始查询在 4.1 中不起作用(再次完全忽略 where 语句),但它是一种可以接受的快速解决方法。

    希望这对其他人有所帮助,YC

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-12
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多