1

我正在使用 EF5 并发现如下问题:

context.Questions
  .OrderBy(x => Guid.NewGuid())
  .Where(x => x.Difficulty == difficulty && x.Format == format);

每个问题都有一个名为持续时间的字段,其值(2、4、6 和 8)以分钟为单位。

我有以下 int 数组: { 4, 0, 1, 2 } 这意味着:

得到 4 个 2 分钟的问题,0 个 4 分钟的问题,1 个 6 分钟的问题和 2 个 8 分钟的问题。

在 .OrderBy 和 .Where 之后,我需要得到提到的 7 个问题。

有没有办法在不加载所有问题或使用 4 个查询的情况下做到这一点?

谢谢你,米格尔

4

3 回答 3

1

这是一种硬编码——但你明白了,并明确地解决了你的问题。您应该能够从这里将其转换为您需要的任何内容。

var questions =  context.Questions .OrderBy(x => Guid.NewGuid())
                        .Where(x => x.Difficulty == difficulty && x.Format == format);

var selectedQuestions = questions.Where(q => q.Duration == 2).Take(questionArray[0])
    .Union(questions.Where(q => q.Duration == 4).Take(questionArray[1]))
    .Union(questions.Where(q => q.Duration == 6).Take(questionArray[2]))
    .Union(questions.Where(q => q.Duration == 8).Take(questionArray[3]));

由于您从不枚举可查询对象,因此 EF 将在 sql 中执行所有这些联合,并在一次调用中获取所有数据。

产生的SQL:

SELECT [Distinct3].[C1] AS [C1],
       [Distinct3].[C2] AS [C2],
       [Distinct3].[C3] AS [C3],
       [Distinct3].[C4] AS [C4]
FROM   (SELECT DISTINCT [UnionAll3].[C1] AS [C1],
                        [UnionAll3].[C2] AS [C2],
                        [UnionAll3].[C3] AS [C3],
                        [UnionAll3].[C4] AS [C4]
        FROM   (SELECT   [Distinct2].[C1] AS [C1],
                         [Distinct2].[C2] AS [C2],
                         [Distinct2].[C3] AS [C3],
                         [Distinct2].[C4] AS [C4]
                FROM     (SELECT DISTINCT [UnionAll2].[C1] AS [C1],
                                          [UnionAll2].[C2] AS [C2],
                                          [UnionAll2].[C3] AS [C3],
                                          [UnionAll2].[C4] AS [C4]
                          FROM   (SELECT   [Distinct1].[C1] AS [C1],
                                           [Distinct1].[C2] AS [C2],
                                           [Distinct1].[C3] AS [C3],
                                           [Distinct1].[C4] AS [C4]
                                  FROM     (SELECT DISTINCT [UnionAll1].[Id] AS [C1],
                                                            [UnionAll1].[Duration] AS [C2],
                                                            [UnionAll1].[Difficulty] AS [C3],
                                                            [UnionAll1].[Format] AS [C4]
                                            FROM   (SELECT   TOP (4) [Project1].[Id] AS [Id],
                                                                     [Project1].[Duration] AS [Duration],
                                                                     [Project1].[Difficulty] AS [Difficulty],
                                                                     [Project1].[Format] AS [Format]
                                                    FROM     (SELECT NEWID() AS [C1],
                                                                     [Extent1].[Id] AS [Id],
                                                                     [Extent1].[Duration] AS [Duration],
                                                                     [Extent1].[Difficulty] AS [Difficulty],
                                                                     [Extent1].[Format] AS [Format]
                                                              FROM   [dbo].[Questions] AS [Extent1]
                                                              WHERE  ([Extent1].[Difficulty] = @p__linq__0)
                                                                     AND ([Extent1].[Format] = @p__linq__1)
                                                                     AND (2 = [Extent1].[Duration])) AS [Project1]
                                                    ORDER BY [Project1].[C1] ASC
                                                    UNION ALL
                                                    SELECT   TOP (0) [Project3].[Id] AS [Id],
                                                                     [Project3].[Duration] AS [Duration],
                                                                     [Project3].[Difficulty] AS [Difficulty],
                                                                     [Project3].[Format] AS [Format]
                                                    FROM     (SELECT NEWID() AS [C1],
                                                                     [Extent2].[Id] AS [Id],
                                                                     [Extent2].[Duration] AS [Duration],
                                                                     [Extent2].[Difficulty] AS [Difficulty],
                                                                     [Extent2].[Format] AS [Format]
                                                              FROM   [dbo].[Questions] AS [Extent2]
                                                              WHERE  ([Extent2].[Difficulty] = @p__linq__2)
                                                                     AND ([Extent2].[Format] = @p__linq__3)
                                                                     AND (4 = [Extent2].[Duration])) AS [Project3]
                                                    ORDER BY [Project3].[C1] ASC) AS [UnionAll1]) AS [Distinct1]
                                  UNION ALL
                                  SELECT   TOP (1) [Project7].[Id] AS [Id],
                                                   [Project7].[Duration] AS [Duration],
                                                   [Project7].[Difficulty] AS [Difficulty],
                                                   [Project7].[Format] AS [Format]
                                  FROM     (SELECT NEWID() AS [C1],
                                                   [Extent3].[Id] AS [Id],
                                                   [Extent3].[Duration] AS [Duration],
                                                   [Extent3].[Difficulty] AS [Difficulty],
                                                   [Extent3].[Format] AS [Format]
                                            FROM   [dbo].[Questions] AS [Extent3]
                                            WHERE  ([Extent3].[Difficulty] = @p__linq__4)
                                                   AND ([Extent3].[Format] = @p__linq__5)
                                                   AND (6 = [Extent3].[Duration])) AS [Project7]
                                  ORDER BY [Project7].[C1] ASC) AS [UnionAll2]) AS [Distinct2]
                UNION ALL
                SELECT   TOP (2) [Project11].[Id] AS [Id],
                                 [Project11].[Duration] AS [Duration],
                                 [Project11].[Difficulty] AS [Difficulty],
                                 [Project11].[Format] AS [Format]
                FROM     (SELECT NEWID() AS [C1],
                                 [Extent4].[Id] AS [Id],
                                 [Extent4].[Duration] AS [Duration],
                                 [Extent4].[Difficulty] AS [Difficulty],
                                 [Extent4].[Format] AS [Format]
                          FROM   [dbo].[Questions] AS [Extent4]
                          WHERE  ([Extent4].[Difficulty] = @p__linq__6)
                                 AND ([Extent4].[Format] = @p__linq__7)
                                 AND (8 = [Extent4].[Duration])) AS [Project11]
                ORDER BY [Project11].[C1] ASC) AS [UnionAll3]) AS [Distinct3];
于 2013-03-05T12:34:51.960 回答
0

为什么不只获取每种类型的 4 个(或数组中的最大值)问题并在客户端上进行过滤?有 16 个结果应该很便宜 - 您可以使用 linq 分组按分钟对它们进行分组,然后应该很容易。这里另一个有趣的点是排序...如果您有超过 4 个问题,但在选择时总是对它们进行排序,您会看到前 4 个问题吗?

于 2013-03-05T19:33:53.817 回答
0

我的查询有点复杂。基本上,我最终得到以下结果:

context.Questions
  .OrderBy(x => Guid.NewGuid())
  .Where(x =>
    x.AccessLevel >= accessLevel &&
    x.Enabled == true &&
    x.QuestionFormat == questionFormat
    x.Theme.Id == themeId
  )
  .Select(x => new {
    Answers = x.Answers.Select(y => new {
      Correct = y.Correct,
      Packs = y.Packs.SelectMany(z => z.Files, (z, v) => new {
        Id = z.Id,
        File = new { Key = v.Key, Mime = v.Mime }
      }),
      Text = y.Text
    }),
    Duration = x.Duration,
    Note = x.Note,
    Text = x.Text,
    Packs = x.Packs.SelectMany(y => y.Files, (y, z) => new {
      Id = y.Id,
      File = new { Key = z.Key, Mime = z.Mime }
    })
   })
   .GroupBy(x => x.Duration);

所以我随机排序问题并过滤它们。

然后我得到每个问题的答案......

每个问题和答案都有一些与之关联的文件。

我将所有文件放在一张桌子上。这就是为什么我的查询中有包和文件的原因。

我只加载文件键和哑剧。不是数据。

所以你的建议是把所有问题按时间分组,对吧?

事实上,在做 AccessLevel / Enabled / QuestionFormat / Theme 过滤之后我永远不会有这么多问题......

因此,我可以像在此查询末尾所做的那样按 Duration 对它们进行分组。

根据我在开头发布的数组,获取每个持续时间的问题数量的快速方法是什么?

谢谢你,米格尔

于 2013-03-05T23:44:05.963 回答