如何在EF Core中将此SQL查询转换为LINQ查询?

时间:2019-04-23 16:21:48

标签: c# sql linq entity-framework-core

我有下表:

data ThingAtoThinBMapping = ThingAtoThinBMapping {
      thingA :: Text
    , thingB :: Text
} deriving (Eq, Show, Read)

instance FromNamedRecord ThingAtoThinBMapping where
    parseNamedRecord r = ThingAtoThinBMapping 
        <$> r .: "thing_a"
        <*> r .: "thing_b"

printABMap = do
    csvData <- BL.readFile "reallywide.csv"
    case decodeByNameWith decodeOpts csvData of
        Left err -> putStrLn err
        Right (h, v) -> do
            putStrLn $ show h
            V.forM_ v $ \ m ->
                putStrLn $ show (thingA m, thingB m)

而且我有EF Core映射实体可以映射到该表。

我需要将此SQL查询转换为ef核心Linq等效查询。

Indicators(A INT, B INT, C INT, D INT, TimeInsertedLocal DateTime) . 

这是实体:

SELECT A, B, C, D, TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >= 
(   
    SELECT MAX(I.TimeInsertedLocal) 
    FROM Indicators AS I
) 

如何编写LINQ查询,以便EF Core生成相同的查询或达到相同结果的更好查询?

2 个答案:

答案 0 :(得分:4)

这实际上是一对一的翻译。

SQL查询

SELECT A, B, C, D , TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >= 
(   
    SELECT MAX(I.TimeInsertedLocal) 
    FROM Indicators AS I
)

EF Core LINQ查询:

var indicators = dbContext.Set<Indicator>();
var query = indicators
    .Where(i => i.TimeInsertedLocal >= indicators.Max(i2 => (DateTime?)i2.TimeInsertedLocal));

EF Core生成的SQL查询:

SELECT [i].[A], [i].[B], [i].[C], [i].[D], [i].[TimeInsertedLocal]
FROM [Indicators] AS [i]
WHERE [i].[TimeInsertedLocal] >= (
    SELECT MAX([i2].[TimeInsertedLocal])
    FROM [Indicators] AS [i2]
)

LINQ查询中唯一的特定细节是在DateTime?中进行的Max强制转换,否则EF Core将尝试模拟LINQ Max方法的抛出行为并评估查询client side

答案 1 :(得分:1)

当然没有指标的TimeInsertedLocal值大于所有指标中的TimeInsertedLocal的最大值。

但是,可能有几个指标的值等于TimeInsertedLocal的最大值。

在这种情况下,您需要将具有相同的TimeInsertedLocal的指标组组成,并取最大的一组。

var indicatorsWithLargestTimeInsertedLocal = myDbContext.Indicators
    // make groups of Indicators with same TimeInsertedLocal:
    .GroupBy(indicator => indicator.TimeInsertedLocal)

    // put the group with the largest TimeInsertedLocal first:
    .OrderByDescending(group => group.Key)

    // The first group of indicators, is the group with the largest value of TimeInsertedLocal
    .FirstOrDefault();

如果您确定TimeInsertedLocal是唯一的,则不必使用GroupBy,只有一个指标具有最大的TimeInsertedLocal

var indicatorWithLargestTimeInsertedLocal = myDbContext.Indicators
    .OrderByDescending(indicator => indicator.TimeInsertedLocal)
    .FirstOrDefault();