C# SQL:选择id,MAX(y.DateCreated)从x向左在Linq中加入y?

C# SQL:选择id,MAX(y.DateCreated)从x向左在Linq中加入y?,c#,entity-framework,linq,C#,Entity Framework,Linq,我似乎无法将此SQL重写为EF Linq: 选择对话.Id 从对话左侧加入消息 在对话中.Id=Message.ConversationId 按对话分组。Id 按最大值排序(Message.DateCreated)说明 我认为这样做会奏效: \u dbContext.Conversation .OrderByDescending(c=>c.Messages.DefaultIfEmpty().Max(m=>m.DateCreated)) .选择(cm=>cm.Id); 但这给了我一个错误Sys

我似乎无法将此SQL重写为EF Linq:

选择对话.Id
从对话左侧加入消息
在对话中.Id=Message.ConversationId
按对话分组。Id
按最大值排序(Message.DateCreated)说明
我认为这样做会奏效:

\u dbContext.Conversation
.OrderByDescending(c=>c.Messages.DefaultIfEmpty().Max(m=>m.DateCreated))
.选择(cm=>cm.Id);
但这给了我一个错误
System.invalidoOperationException:序列不包含任何元素。

还包括:

\u dbContext.Conversation
.Select(c=>new{c.Id,MaxDate=c.Messages.DefaultIfEmpty().Max(m=>m.DateCreated)})
.OrderByDescending(c=>c.MaxDate)
.选择(cm=>cm.Id);
但这给了我
System.ArgumentException:至少有一个对象必须实现IComparable。

正确的方法是什么?

你能试试这个吗:

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);
这可能无法编译,因为我没有测试这一点的代码(比如小提琴)

您可以试试这个吗:

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

这可能无法编译,因为我没有代码来测试这一点(就像小提琴一样)

不过你很接近了,只需删除
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

不过你很接近了,只需放下
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

我相信这将生成您正在寻找的SQL(加上或减去一个嵌套子查询):

但是,在LINQ中,可以使用组联接而不是常规联接。这也应该满足您的需要,但是在SQL中使用了一个子选择,所以我不确定哪一个在服务器上更有效。共同的智慧似乎是join更好,但是跟随group by可能会让它变得毫无意义,就像一个足够现代的优化器一样。我发现的另一篇帖子说子查询(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;

我相信这将生成您正在寻找的SQL(加上或减去一个嵌套子查询):

但是,在LINQ中,可以使用组联接而不是常规联接。这也应该满足您的需要,但是在SQL中使用了一个子选择,所以我不确定哪一个在服务器上更有效。共同的智慧似乎是join更好,但是跟随group by可能会让它变得毫无意义,就像一个足够现代的优化器一样。我发现的另一篇帖子说子查询(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;


也许我的朋友能帮你?我想,你可以从这篇文章中得到一些想法@NetMage我认为这与Guaravsa的查询是一致的。我很接近,但还没有弄清楚为什么我的DefaultIfEmpty不能处理Max和一组空的子记录。消息的数据类型是什么?那么“默认”是什么呢?对此调用
Max
的结果是什么?(或者,
MaxDate
的类型是什么?)另外,当没有匹配的
消息行时,
MAX
的计算结果是什么,以及结果的顺序是什么?也许我的方法可以帮助你?我想,你可能会从这篇文章中得到一些想法@NetMage我认为这与Guaravsa的查询是一致的。我很接近,但还没有弄清楚为什么我的DefaultIfEmpty不能处理Max和一组空的子记录。消息的数据类型是什么?那么“默认”是什么呢?对此调用
Max
的结果是什么?(或者,
MaxDate
的类型是什么?)另外,当没有匹配的
Message
行时,
MAX
的计算结果是什么,以及结果的顺序是什么?您只需在r.Messages.DefaultIfEmpty()
中执行
表单ru即可。@Gauravsa这非常接近,谢谢!我还没有成功地让DefaultIfEmpty处理一组丢失的子记录,但是---仍在处理。您可以在r.Messages.DefaultIfEmpty()中执行表单ru。@Gauravsa这非常接近,谢谢!我还没有成功地让DefaultIfEmpty处理一组丢失的子记录,不过,我仍然在处理它。我认为这遗漏了左边的连接。如果我将其切换到
MaxDateCreated=con.Messages.Select(x=>x.DateCreated).DefaultIfEmpty(DateTime.MaxValue).Max()
,这将起作用。但是,在这两种情况下,
Max()
都是在本地而不是在数据库中进行计算的。不,不是这样。我用生成的查询编辑了文章,这相当于您想要的左连接结果。你不需要
DefaultIfEmpty
,因为EF已经可以为你做了。我得到了一个
System.invalidoOperationException:序列不包含任何元素。
当它遇到一组空的
.Messages
时,在
Max()上出错。我认为这错过了左边的连接。如果我将其切换到
MaxDateCreated=con.Messages.Select(x=>x.DateCreated).DefaultIfEmpty(DateTime.MaxValue).Max()
,这将起作用。但是,在这两种情况下,
Max()
都是在本地而不是在数据库中进行计算的。不,不是这样。我用生成的查询编辑了文章,这相当于您想要的左连接结果。你不需要
DefaultIfEmpty
,因为EF已经可以为你做了。我得到了一个
System.invalidoOperationException:序列不包含任何元素。
当它遇到一组空的
.Messages
时,在
Max()上出现错误。
。谢谢,第一个版本似乎可以工作。我在
DefaultIfEmpty
中添加了一个参数,这样空值就会出现在顶部,LINQ无法将其转换为EF,但我可以处理这个问题。(第二个不处理空的消息集)我得到了一个几乎相同的查询,但它不起作用——我的查询和你的查询之间的唯一区别是,投影在不同的地方发生的方式不同。我想我需要在查询的每一步都尽可能地简化这些内容。@mikebridge第二个在