EF代码优先:如何获取随机行


79

如何建立查询以检索随机行?

如果我要用SQL编写它,那么我将对newid()进行排序,并从顶部砍掉n行。无论如何要先在EF代码中执行此操作?

我尝试创建使用newid()的查询并使用DbSet.SqlQuery()执行它。虽然有效,但并不是最干净的解决方案。

另外,尝试检索所有行并按新的GUID对它们进行排序。尽管行数很小,但是它仍然不是一个好的解决方案。

有任何想法吗?



Answers:


162

只需致电:

something.OrderBy(r => Guid.NewGuid()).Take(5)

嗨,它工作正常,但是当表有更多行时,这会很快
吗?

3
看到这个问题,很不幸被打破了。看起来OrderBy假设排名函数是稳定的,而随机生成器则不是这种情况。将实体的Linq转换为sql查询,该查询可能会为同一实体获得不同的排名(一旦查询使用Include)。然后,它导致实体在结果列表中重复。
弗雷德里克

1
不知道对于需要随机排列的固定行的任务我是否会相信-我可能会选择用stackoverflow.com/a/654910/12484stackoverflow.com/a/648247/12484代替-但是这种简单的方法可以满足我的需求,它需要为非面向客户的功能使用一个伪随机行。+1。
乔恩·施耐德

@Toolkit可能并不那么奇怪,如果Entity没有与Oracle等效的东西Guid.NewGuid()(意味着,LinqToSql或将其变成任何东西,NEWID()但没有人为Oracle编程相同的东西)。
drzaus17年

这种方法有效吗?我发现在其他地方,出于某种性能考虑,不建议使用此方法。
Mohammed Noureldin

38

比较两个选项:


跳过(随机行数)

方法

private T getRandomEntity<T>(IGenericRepository<T> repo) where T : EntityWithPk<Guid> {
    var skip = (int)(rand.NextDouble() * repo.Items.Count());
    return repo.Items.OrderBy(o => o.ID).Skip(skip).Take(1).First();
}
  • 进行2次查询

生成的SQL

SELECT [GroupBy1].[A1] AS [C1]
FROM   (SELECT COUNT(1) AS [A1]
        FROM   [dbo].[People] AS [Extent1]) AS [GroupBy1];

SELECT TOP (1) [Extent1].[ID]            AS [ID],
               [Extent1].[Name]          AS [Name],
               [Extent1].[Age]           AS [Age],
               [Extent1].[FavoriteColor] AS [FavoriteColor]
FROM   (SELECT [Extent1].[ID]                                  AS [ID],
               [Extent1].[Name]                                AS [Name],
               [Extent1].[Age]                                 AS [Age],
               [Extent1].[FavoriteColor]                       AS [FavoriteColor],
               row_number() OVER (ORDER BY [Extent1].[ID] ASC) AS [row_number]
        FROM   [dbo].[People] AS [Extent1]) AS [Extent1]
WHERE  [Extent1].[row_number] > 15
ORDER  BY [Extent1].[ID] ASC;

引导

方法

private T getRandomEntityInPlace<T>(IGenericRepository<T> repo) {
    return repo.Items.OrderBy(o => Guid.NewGuid()).First();
}

生成的SQL

SELECT TOP (1) [Project1].[ID]            AS [ID],
               [Project1].[Name]          AS [Name],
               [Project1].[Age]           AS [Age],
               [Project1].[FavoriteColor] AS [FavoriteColor]
FROM   (SELECT NEWID()                   AS [C1],
               [Extent1].[ID]            AS [ID],
               [Extent1].[Name]          AS [Name],
               [Extent1].[Age]           AS [Age],
               [Extent1].[FavoriteColor] AS [FavoriteColor]
        FROM   [dbo].[People] AS [Extent1]) AS [Project1]
ORDER  BY [Project1].[C1] ASC

1
感谢您的比较,它确实有帮助
郝博

这是正确的答案,不建议使用带标记的答案,因为它可能会导致某些性能问题。
雅各布

1
问题以复数形式表示“行”,您如何将其应用于解决方案?在我看来,我将不得不多次执行相同的SQL,因为OrderBy(o => o.ID).Skip(skip).Take(5)这并不是真正随机的,这可能会成为性能瓶颈。
Mike Mat

@MikeMat只需删除“ .First()”。我正在与其他一些我不再看到的答案进行比较,因此您的观点得到了双重验证。但是NewGuid解决方案不会出现您描述的问题。
drzaus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.