开发者

Linq query with different behavior in 4.0 compared to 3.5 (let keyword issue?)

开发者 https://www.devze.com 2023-03-22 04:40 出处:网络
Enter code here`I have several Linq queries that use the \'let\' keyword. They work fine in 3.5 but I am seeing a very strange behavior in 4.0.

Enter code here`I have several Linq queries that use the 'let' keyword. They work fine in 3.5 but I am seeing a very strange behavior in 4.0.

Example:

 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
                                            &&开发者_Python百科 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);

This allows to enumerate through 2 nested loops. One for each option and one for each region adjustement within an option.

foreach (var bookOption in query)

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

The problem in 4.0 is that the SQL generated is a SELECT FROM RegionPriceAdjustment table WITHOUT any WHERE clause (traced with the Profiler). Which means the the command times out (and is wrong anyway because there is no sign of the other part of the query).

I have tried to replace the "let" by .Include and this works with lazy loading enabled but it generates a dynamic sql statement for each PriceType (there are 8 so it's not very efficient). I have tried to disable lazy loading but this definitely gives me an error as PriceType does not get loaded. I have tried to use two select separated by into but I get the same problem.

BTW in 4.0, I am using POCOs and EntityFramework DLL with the DbContext object. I have not tried with ObjectContext but that should not make any difference since DbContext wraps around ObjectContext.

Any clue as to why it does that? Any suggestions?

Thanks, Yves

Edited:

Here is the SQL with 3.5:

[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

Here is what I only get with 4.1 (using POCO's):

    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]

As you can see, there is no WHERE clause and no trace of the rest of the SQL......


I have found a workaround though. My new query is as follows:

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); 

Note in the third line that I am querying from xVehicleOption instead of this.entities., therefore doing an inner join. Of course, I don't need the lines that are commented out now. I found this solution in reading the excellent article by Craig Stuntz:

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

Of course, according to Craig, my query can be even more simplified but I wanted to keep most of it as it was for understandability reasons.

This still does not explain why the original query does not work in 4.1 (again the where statements are completely ignored) but it is an acceptable quick workaround.

Hope this helps others, YC

0

精彩评论

暂无评论...
验证码 换一张
取 消