代码之家  ›  专栏  ›  技术社区  ›  Yehia A.Salam

分组并从两个表Linq中选择第一个

  •  0
  • Yehia A.Salam  · 技术社区  · 6 年前

    0两个实体:访问者和聊天信息

    Visitor包含访问者信息,ChatMessages包含实际的聊天内容。

    enter image description here

    1第一次尝试

    from c in ChatMessages
    orderby c.CreatedAt descending 
    group c by c.VisitorId  into x
    select x.First()
    

    这让我得到了按访客id分组的最新消息列表:

    enter image description here

    很酷,特别是生成了简短的sql查询:

    SELECT [t3].[test], [t3].[Id], [t3].[Message], [t3].[UserId], [t3].[VisitorId], [t3].[isDeleted] AS [IsDeleted], [t3].[CreatedAt], [t3].[CreatedBy], [t3].[LastUpdatedAt], [t3].[LastUpdatedBy], [t3].[isFromVisitor] AS [IsFromVisitor]
    FROM (
        SELECT [t0].[VisitorId]
        FROM [ChatMessages] AS [t0]
        GROUP BY [t0].[VisitorId]
        ) AS [t1]
    OUTER APPLY (
        SELECT TOP (1) 1 AS [test], [t2].[Id], [t2].[Message], [t2].[UserId], [t2].[VisitorId], [t2].[isDeleted], [t2].[CreatedAt], [t2].[CreatedBy], [t2].[LastUpdatedAt], [t2].[LastUpdatedBy], [t2].[isFromVisitor]
        FROM [ChatMessages] AS [t2]
        WHERE (([t1].[VisitorId] IS NULL) AND ([t2].[VisitorId] IS NULL)) OR (([t1].[VisitorId] IS NOT NULL) AND ([t2].[VisitorId] IS NOT NULL) AND ([t1].[VisitorId] = [t2].[VisitorId]))
        ORDER BY [t2].[CreatedAt] DESC
        ) AS [t3]
    ORDER BY [t3].[CreatedAt] DESC
    

    2第二次尝试,加入访客表

    from c in ChatMessages
    join v in Visitors on  c.VisitorId equals v.Id 
    orderby c.CreatedAt descending 
    group new {Message = c, Visitor = v} by c.Visitor.Id  into x
    select x
    

    产生了我想要的:

    enter image description here

    SELECT [t2].[Id] AS [Key]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    GROUP BY [t2].[Id]
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 1
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 2
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 3
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 4
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 5
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 6
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 7
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 8
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 9
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 10
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 11
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 12
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 13
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 14
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 15
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 16
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 17
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 18
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 19
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    GO
    
    -- Region Parameters
    DECLARE @x1 BigInt = 20
    -- EndRegion
    SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
    FROM [ChatMessages] AS [t0]
    INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
    LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
    WHERE @x1 = [t2].[Id]
    ORDER BY [t0].[CreatedAt] DESC
    
    

    我不想在数据库中出现一个我不想火的查询。此外,当在asp.net核心应用程序,我得到一个例外 EF.Property called with wrong property name. ,不确定原因:

    crit: converse_app.Controllers.VisitorsController[0]
          There was an error on 'GetVisitorsAsync' invocation: System.InvalidOperationException: EF.Property called with wrong property name.
             at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
             at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.Expand(Expression source, MemberIdentity member)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.VisitMember(MemberExpression memberExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.VisitMember(MemberExpression memberExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.Expand(SelectExpression selectExpression, Expression lambdaBody)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.RemapLambdaBody(ShapedQueryExpression shapedQueryExpression, LambdaExpression lambdaExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateGroupBy(ShapedQueryExpression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
             at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
             at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
             at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
             at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
             at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
             at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
             at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
             at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
             at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
             at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
             at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
             at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
             at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
             at converse_app.Controllers.VisitorsController.GetVisitorsAsync(Int32 pageSize, Int32 pageNumber
    
    

    我使用的是.NETCore3Preview8和EFCore3Preview8,并在MSSQL上运行。

    0 回复  |  直到 6 年前
        1
  •  3
  •   Ivan Stoev    6 年前

    您要标准地查找的查询在linqtoentities(EF)中用类似于(no join s、 没有 GroupBy ,使用导航属性):

    var query = context.Visitors
        .Select(v => new
        {
            Visitor = v,
            Message = v.VisitorChatMessages
                .OrderByDescending(m => m.CreatedAt)
                .FirstOrDefault()
        });
    

    但这是个陷阱。产生的查询效率很低,直到现在,EF+SQL的查询效率仍然很低。

    但EF Core 3.0正朝着积极的方向发展!通常(现在仍然)我不推荐使用efcore3.0的预览版(beta版),因为它们重写了整个查询翻译/处理管道,所以很多事情都不能按预期工作。

    但是今天我把我的EF Core测试环境更新到efcore3.0 预览9

      SELECT [v].[Id], [v].[CreatedAt], [v].[CreatedBy], [v].[Email], [v].[Fingerprint], [v].[IP], [v].[IsDeleted], [v].[LastUpdatedAt], [v].[LastUpdatedBy], [v].[Name], [v].[Phone], [t0].[Id], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[IsDeleted], [t0].[IsFromVisitor], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[Message], [t0].[UserId], [t0].[VisitorId]
      FROM [Visitors] AS [v]
      LEFT JOIN (
          SELECT [t].[Id], [t].[CreatedAt], [t].[CreatedBy], [t].[IsDeleted], [t].[IsFromVisitor], [t].[LastUpdatedAt], [t].[LastUpdatedBy], [t].[Message], [t].[UserId], [t].[VisitorId]
          FROM (
              SELECT [c].[Id], [c].[CreatedAt], [c].[CreatedBy], [c].[IsDeleted], [c].[IsFromVisitor], [c].[LastUpdatedAt], [c].[LastUpdatedBy], [c].[Message], [c].[UserId], [c].[VisitorId], ROW_NUMBER() OVER(PARTITION BY [c].[VisitorId] ORDER BY [c].[CreatedAt] DESC) AS [row]
              FROM [ChatMessages] AS [c]
          ) AS [t]
          WHERE [t].[row] <= 1
      ) AS [t0] ON [v].[Id] = [t0].[VisitorId]
    

    ROW_NUMBER() OVER (PARTITION BY ORDER BY) 构造。这是EF查询翻译有史以来第一次这么做。我很兴奋。干得好,英孚核心团队!


    与您的第一个查询完全相同(btw在Preview9中因运行时异常而失败)

    from c in context.ChatMessages
    orderby c.CreatedAt descending 
    group c by c.VisitorId  into x
    select x.First()
    

    但是有更多的信息

    from v in context.Visitors
    from c in v.VisitorChatMessages
        .OrderByDescending(c => c.CreatedAt)
        .Take(1)
    orderby c.CreatedAt descending
    select new
    {
        Visitor = v,
        Message = c
    })
    

    生成的SQL基本上是一样的-只是 LEFT OUTER JOIN 变成 INNER JOIN ORDER BY 最后。

    看起来是这样的,要想让它成功,就必须避免 分组 和使用 GroupJoin (哪个集合导航属性在LINQ to Entities查询中表示)或 SelectMany 以达到所需的分组。

        2
  •  1
  •   Steve Py    6 年前

    您应该能够通过关联获取访问者信息,而无需显式地尝试加入/分组。

    很抱歉切换到流畅的语法,我真的不喜欢linql,它似乎总是被迫通过它做任何事情。。。:)

    from c in ChatMessages
    orderby c.CreatedAt descending 
    group c by c.VisitorId  into x
    select x.First()
    

    var groupedMessages = context.ChatMessages
        .OrderByDescending(c => c.CreatedAt)
        .GroupBy(c => c.VisitorId)
        .First();
    

    var groupedMessages = context.ChatMessages
        .OrderByDescending(c => c.CreatedAt)
        .GroupBy(c => c.Visitor)
        .First();
    

    这将为您提供一个作为访问者实体的密钥,以及该访问者的消息。 然而,这多少回避了一个问题,为什么?

    var visitorsWithMessages = context.Visitors.Include(v => v.VisitorChatMessages);
    

    var visitorsWithMessages = context.Visitors
       // insert .Where() clause here to filter which Visitors we care to retrieve...
       .Select(v => new VisitorViewModel
       {
          Id = v.Id,
          Name = v.Name,
          RecentChatMessages = v.VisitorChatMessages
             .OrderByDescending(c => c.CreatedAt)
             .Select(c => new ChatMessageViewModel
             {
                Id = c.Id,
                Message = c.Message,
                CreatedAt = c.CreatedAt,
                CreatedBy = c.User.UserName ?? "Anonymous"
             }).Take(10).ToList()
        }).ToList();
    

    它使用projection和EF的映射关系来获取访问者列表和最多10条他们最近的聊天消息。我填充包含我关心的字段的简单POCO视图模型类。这些视图模型可以安全地从方法中返回或序列化到视图/API使用者,而不会有延迟加载的风险。如果我只需要数据而不需要发送到任何地方,我可以使用匿名类型来获取我关心的字段。我们不需要显式地将实体连接在一起,您只需要对故意没有映射FK关系的实体执行此操作。我们也不需要故意急于加载实体。这个 Select 将为我们需要的列组成一个优化的SQL语句。

    您可以在视图中使用这些结果,并基于Visitor+消息进行渲染,或者如果您想将每个访问者的列表10个最新消息/w访问者详细信息显示为一个扁平的消息列表,则可以更深入地研究:

    编辑:在 .SelectMany

    var recentMessages = context.Visitors
       .SelectMany(v => v.VisitorChatMessages
          .OrderByDescending(c => c.CreatedAt)
          .Select(c => new VisitorChatMessageViewModel
          {
              Id = c.Id,
              VisitorId = c.Visitor.Id,
              Message = c.Message,
              CreatedAt = c.CreatedAt,
              CreatedBy = c.User.UserName ?? "Anonymous",
              Visitor = c.Visitor.Name
          }).Take(10)
        }).ToList();
    

    但不知道如何在linql中做到这一点。:)

    编辑:最后一个示例将给出最后10条消息及其适用的访问者详细信息。(姓名)

    例如,要获取最后100条消息并按访问者分组:

    var recentMessages = context.Visitors
       .SelectMany(v => v.VisitorChatMessages
          .OrderByDescending(c => c.CreatedAt)
          .Select(c => new VisitorChatMessageViewModel
          {
              Id = c.Id,
              VisitorId = c.Visitor.Id,
              Message = c.Message,
              CreatedAt = c.CreatedAt,
              CreatedBy = c.User.UserName ?? "Anonymous",
              Visitor = c.Visitor.Name // Visitor Name, or could be a ViewModel for more info about Visitor...
          }).Take(100)
        }).GroupBy(x => x.Visitor).ToList();
    

    如果您为访问者选择VisitorViewModel而不是“”。访客姓名“然后,您的分组键将可以访问Name、Id等,无论您从关联的访问者中选择什么。