簡體   English   中英

LINQ-to-SQL:Select 使用 LINQ 查詢的每個 GROUP 頂行的多個屬性

[英]LINQ-to-SQL: Select mulitple properties from top row of each GROUP using LINQ query

我有兩張表,Apps 和 AppGooglePlayMetadatas [AGPM],一個 Apps 行有很多 AGPM。 我想 select 一組應用程序,並且對於每個應用程序,還從每個最近的 AGPM 行返回一些屬性。 我可以用這段代碼做到這一點:

Apps
.Select(a => new
{
    a.Name,
    DatePublished = a.AppGooglePlayMetadatas.OrderByDescending(agpm => agpm.DatePublished).Select(agpm => agpm.DatePublished).First(),
    CollectionDate = a.AppGooglePlayMetadatas.OrderByDescending(agpm => agpm.DatePublished).Select(agpm => agpm.CollectionDate).First(),
})

但這很丑陋,不能很好地擴展,並導致(可能)效率低下 SQL 訂購完成兩次:

SELECT [t0].[Name], (
    SELECT TOP (1) [t1].[DatePublished]
    FROM [AppGooglePlayMetadata] AS [t1]
    WHERE [t1].[AppId] = [t0].[AppId]
    ORDER BY [t1].[DatePublished] DESC
    ) AS [DatePublished], (
    SELECT TOP (1) [t2].[CollectionDate]
    FROM [AppGooglePlayMetadata] AS [t2]
    WHERE [t2].[AppId] = [t0].[AppId]
    ORDER BY [t2].[DatePublished] DESC
    ) AS [CollectionDate]
FROM [Apps] AS [t0]

這可以像這樣寫得更簡潔一些,但仍然會導致兩個 ORDER BY 語句:

Apps
.Select(a => new
{
    App = a,
    Latest = a.AppGooglePlayMetadatas.OrderByDescending(agpm => agpm.DatePublished).First()
})
.Select(a => new {
    a.App.Name,
    a.Latest.CollectionDate,
    a.Latest.DatePublished,
})

我正在尋找一種方法來查詢連接表中特定行的多個屬性,從而生成高效的 SQL 查詢。 如果我要在 SQL 中寫這個,我相信我可以像這樣最有效地做到這一點:

SELECT TOP 100 a.Name, agpm.CollectionDate, agpm.DatePublished
FROM Apps AS a
CROSS APPLY (
    SELECT TOP 1 DatePublished, CollectionDate
    FROM AppGooglePlayMetadata AS agpm
    WHERE a.AppId = agpm.AppId
    ORDER BY DatePublished DESC
) AS agpm

不確定在這種情況下是否有可能讓 LINQ 生成 SQL 如此高效,但希望一些天才可以幫助我,謝謝!

您可以嘗試以下方法:

var result = 
    Apps.Join(
        AppGooglePlayMetadata
            .GroupBy(x => x.AppId)
            .Select(grp => grp
                .OrderByDescending(x => x.DatePublished)
                .First()),
        x => x.AppId,
        x => x.AppId,
        (app, meta) => new { app.AppId, meta.DatePublished, meta.CollectionDate });

這會讓你得到一個有效的 SQL 聲明嗎?

在實體框架中獲取“項目及其子項目”,如“學校及其學生”、“客戶及其訂單”、“應用程序及其 AGPM”,通常使用virtual ICollection<...>那是一對多關系的一方面。 實體框架會將其轉換為正確的 GroupJoin。

如果您不想使用virtual ICollection<...> ,例如因為您認為可以更高效地執行此操作,請考慮自己執行 GroupJoin:

var result = Apps.GroupJoin(         // GroupJoin Apps
AppGooglePlayMetadatas,              // with AGPMs

app => app.Id,                       // from every App take the primary key
apgm => apgm.AppId,                  // from every Agpm take the foreign key to App

(app, AgpmsOfThisApp) => new         // for every App with its zero or more AGPMs
{                                    // make one new
    AppName = app.Name,
    LatestAgpm = AgpmsOfThisApp.OrderByDescending(agpm => agpm.DatePublished)
        .Select(agpm => new
        {
            CollectionDate = agpm.CollectionDate,
            DatePublished = agpm.DatePublished,
        }}
        .FirstOrDefault(),
})

如果應用程序沒有 AGPM,則根本沒有 LatestAGPM,屬性 KatestAGPM 值將為 null

恕我直言,“帶有最新 AGPM 的應用程序”的概念清晰明了。 用法將是:

textBoxAppName.Text = result.AppName,
testBoxAgpmLastPublished.Text =
   result.LatestAgpm.DatePublished;

如果真想混用App和AGPM的屬性,需要多加一個select:

.Select(appWithItsLatestAgpm => new
{
    Name = appWithItsLatestAgpm.Name,
    CollectionDate = appWithItsLatestAgpm?.CollectionDate,
    DatePublished = appWithItsLatestAgpm?.DatePublished,
})

我不確定這是否會使結果的用戶更清楚。 DatePublished 是 App 的發布日期嗎?

用法將是:

textBoxAppName.Text = result.AppName,
testBoxAgpmLastPublished.Text = result.DatePublished;

這是否證明額外的 Select 是合理的?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM