Linq:如何订购一个表的SUM和另一个表的COUNT

时间:2011-01-17 23:47:00

标签: .net linq-to-sql lambda sql-order-by

根据previous question,我得到了以下LINQ表达式。

Events.Where(Function(e) e.EventDate >= Date.Today) _
            .OrderByDescending(Function(e) (((e.EventVotes.Sum(Function(s) s.Vote)) * 2) + (e.Comments.Count))) _
            .Skip(0) _
            .Take(5)

哪个转换为以下SQL

-- Region Parameters
DECLARE @p0 DateTime2 = '2011-01-17 00:00:00.0000000'
DECLARE @p1 Int = 2
DECLARE @p2 Int = 0
DECLARE @p3 Int = 5
-- EndRegion
SELECT [t3].[ID], [t3].[UserID], [t3].[RegionID], [t3].[LocationID], [t3].[Title], [t3].[Description], [t3].[EventDate], [t3].[URL], [t3].[Phone], [t3].[TicketPriceLow], [t3].[TicketPriceHigh], [t3].[DatePosted], [t3].[isHighlighted]
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY (((
        SELECT SUM([t1].[Vote])
        FROM [dbo].[EventVotes] AS [t1]
        WHERE [t1].[EventID] = [t0].[ID]
        )) * @p1) + ((
        SELECT COUNT(*)
        FROM [dbo].[Comments] AS [t2]
        WHERE [t2].[EventID] = [t0].[ID]
        )) DESC) AS [ROW_NUMBER], [t0].[ID], [t0].[UserID], [t0].[RegionID], [t0].[LocationID], [t0].[Title], [t0].[Description], [t0].[EventDate], [t0].[URL], [t0].[Phone], [t0].[TicketPriceLow], [t0].[TicketPriceHigh], [t0].[DatePosted], [t0].[isHighlighted]
    FROM [dbo].[Events] AS [t0]
    WHERE [t0].[EventDate] >= @p0
    ) AS [t3]
WHERE [t3].[ROW_NUMBER] BETWEEN @p2 + 1 AND @p2 + @p3
ORDER BY [t3].[ROW_NUMBER]

我现在的问题是,在某些事件没有任何投票或评论时进行订购。

这是EventVotes表的样子(完整的)

| UserID | EventID | Vote |    
| 1      | 51      | 1    |   
| 1      | 52      | 1    |   
| 2      | 52      | 1    |   
| 1      | 53      | 1    |   
| 2      | 53      | -1   |   
| 3      | 53      | -1   |

评论表是完全空的,所以因为我们只是在它上面做Count,我们可以假设一切都回来了。

现在,当我运行上面的查询时,结果顺序如下

  

52
  51个
  53个
  1
  2
  3

什么时候“应该”

  

52
  51个
  1
  2
  3
  53

因为事件编号53的投票数为“-1”,而事件编号1,2和3的投票数为“0”

任何人都可以帮忙弄清楚如何增强Linq表达式来解释尚未投票的事件吗?

这是截图

alt text

编辑:

好的,所以我将LinqPad中的查询简化为此,结果是我只得到了三个结果。

Events.OrderByDescending(Function(e) (((e.EventVotes.Sum(Function(s) s.Vote)) * 2) + (e.Comments.Count)))

这告诉我的是,orderby只抓取这三个结果(51,52,53),然后它在订单子句之后附加其余的结果。我需要想办法在Lambda表达式中包含其余的“null”结果。

1 个答案:

答案 0 :(得分:1)

这是一个C#解决方案。我试着把它翻译成VB,但我的VB技能(并且老老实实地想学习它)是零,我放弃了。我将尝试强调帮助翻译的关键点。

以下是完整的陈述:

context.Events.OrderByDescending(e => (((e.EventVotes.Sum(s => (int?)s.Vote) ?? 0) * 2) + e.Comments.Count))

重要的是s.Vote首先被转换为可以为空的整数,以便Sum()的结果是可以为空的整数。可空的结果允许您显式检查null,如果结果确实为null,则对其余计算使用零。

对于VB转换目的,??是一个C#null-coalesce运算符,其中(例如)myNullableIntVar ?? 0求值为myNullableIntVar的值,或者如果它为null,则为0。

这是上面语句生成的SQL,FWIW:

exec sp_executesql N'SELECT [t0].[EventID], [t0].[Name]
FROM [dbo].[Events] AS [t0]
ORDER BY ((COALESCE((
    SELECT SUM([t2].[value])
    FROM (
        SELECT [t1].[Vote] AS [value], [t1].[EventID]
        FROM [dbo].[EventVotes] AS [t1]
        ) AS [t2]
    WHERE [t2].[EventID] = [t0].[EventID]
    ),@p0)) * @p1) + ((
    SELECT COUNT(*)
    FROM [dbo].[Comments] AS [t3]
    WHERE [t3].[EventID] = [t0].[EventID]
    )) DESC',N'@p0 int,@p1 int',@p0=0,@p1=2

由rockinthesixstring编辑

我在下面添加了VB.NET版本 - 这完全符合预期。我试图做DirectCast(s.Vote, Integer?),但它提出错误,指出Integer无法转换为Integer?,所以我不得不采用这种方法。

Events.OrderByDescending(Function(e) (((If(e.EventVotes.Sum(Function(s) s.Vote),
                                           e.EventVotes.Sum(Function(s) s.Vote),
                                           0)) * 2) + e.Comments.Count))

导致此SQL查询

-- Region Parameters
DECLARE @p0 Int = 0
DECLARE @p1 Int = 2
-- EndRegion
SELECT [t0].[ID], [t0].[UserID], [t0].[RegionID], [t0].[LocationID], [t0].[Title], [t0].[Description], [t0].[EventDate], [t0].[URL], [t0].[Phone], [t0].[TicketPriceLow], [t0].[TicketPriceHigh], [t0].[DatePosted], [t0].[isHighlighted]
FROM [dbo].[Events] AS [t0]
ORDER BY ((
    (CASE 
        WHEN (CONVERT(Bit,(
            SELECT SUM([t1].[Vote])
            FROM [dbo].[EventVotes] AS [t1]
            WHERE [t1].[EventID] = [t0].[ID]
            ))) = 1 THEN (
            SELECT SUM([t2].[Vote])
            FROM [dbo].[EventVotes] AS [t2]
            WHERE [t2].[EventID] = [t0].[ID]
            )
        ELSE @p0
     END)) * @p1) + ((
    SELECT COUNT(*)
    FROM [dbo].[Comments] AS [t3]
    WHERE [t3].[EventID] = [t0].[ID]
    )) DESC