SQL: SELECT id, MAX (y.DateCreated) FROM X LEFT JOIN y в Linq? - PullRequest
0 голосов
/ 16 октября 2018

Я не могу переписать этот SQL-код в EF Linq:

SELECT      Conversation.Id
FROM        Conversation LEFT JOIN Message
                ON  Conversation.Id = Message.ConversationId
GROUP BY    Conversation.Id
ORDER BY    MAX(Message.DateCreated) DESC

Я думаю, что-то вроде этого будет работать:

 _dbContext.Conversation
           .OrderByDescending(c => c.Messages.DefaultIfEmpty().Max(m => m.DateCreated))
           .Select(cm => cm.Id);

Но это дает мне ошибку System.InvalidOperationException : Sequence contains no elements.

Также это:

_dbContext.Conversation
          .Select(c => new {c.Id, MaxDate = c.Messages.DefaultIfEmpty().Max(m => m.DateCreated)})
          .OrderByDescending(c => c.MaxDate)
          .Select(cm => cm.Id);

Но это дает мне System.ArgumentException : At least one object must implement IComparable..

Как правильно это сделать?

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Хотя вы близки, просто бросьте DefaultIfEmpty

_dbContext.Conversation.Select(con => new 
    {
        con.Id,
        MaxDateCreated = (DateTime?) con.Messages.Max(msg => msg.DateCreated)
    })
.OrderByDescending(con => con.MaxDateCreated)
.ToArray()

Вот что будет сгенерировано

SELECT 
[Project2].[C1] AS [C1], 
[Project2].[Id] AS [Id], 
[Project2].[C2] AS [C2]
FROM ( SELECT 
    [Project1].[Id] AS [Id], 
    1 AS [C1], 
     CAST( [Project1].[C1] AS datetime2) AS [C2]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        (SELECT 
            MAX([Extent2].[DateCreated]) AS [A1]
            FROM [dbo].[Message] AS [Extent2]
            WHERE [Extent1].[Id] = [Extent2].[ConversationId]) AS [C1]
        FROM [dbo].[Conversation] AS [Extent1]
    )  AS [Project1]
)  AS [Project2]
ORDER BY [Project2].[C2] DESC
0 голосов
/ 17 октября 2018

Я считаю, что это сгенерирует искомый SQL (плюс или минус вложенный подзапрос):

var ans = from c in Conversation
          join m in Message on c.Id equals m.ConversationId into mj
          from m in mj.DefaultIfEmpty()
          group m by c.Id into mg
          orderby mg.Max(m => m.DateCreated) descending
          select mg.Key;

Однако в LINQ вы можете использовать групповое объединение вместо обычного объединения.Это также должно делать то, что вы хотите, но использует подвыбор в SQL, поэтому я не уверен, что более эффективно на сервере.Общая мудрость кажется, что присоединение было лучше, но следование за группой может сделать его спорным, как и достаточно современный оптимизатор.В другом сообщении, которое я нашел, говорилось, что подзапрос (CIS) был намного более эффективным, так что это может быть лучше.

var ans2 = from c in Conversation
           join m in Message on c.Id equals m.ConversationId into mj
           orderby mj.Max(m => m.DateCreated) descending
           select c.Id;
0 голосов
/ 16 октября 2018

Можете ли вы попробовать это:

from r in Conversation
              join ru in Message
              on r.Id equals ru.ConversationId into ps
              from ru in ps.DefaultIfEmpty()
              group ru by new { ru.ConversationId, ru.DateCreated } into rug
              select new {
                  id = ru.ConversationId,
                  datecreated = rug.Max(ru => ru.datecreated)
              }).OrderByDescending(x => x.datecreated);

Это может не скомпилироваться, так как у меня нет кода для проверки (с скрипкой)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...