如何构建一个查询以检索随机行?
如果我要用SQL编写它,那么我会在newid()上放置一个order by,并从顶部切掉n个行。是否有办法在EF代码优先中实现这一点?
我尝试创建一个使用newid()的查询,并使用DbSet.SqlQuery()执行它。虽然它有效,但不是最简洁的解决方案。
另外,尝试检索所有行并按新的guid排序。虽然行数相当小,但仍不是一个好的解决方案。
有什么想法吗?
如何构建一个查询以检索随机行?
如果我要用SQL编写它,那么我会在newid()上放置一个order by,并从顶部切掉n个行。是否有办法在EF代码优先中实现这一点?
我尝试创建一个使用newid()的查询,并使用DbSet.SqlQuery()执行它。虽然它有效,但不是最简洁的解决方案。
另外,尝试检索所有行并按新的guid排序。虽然行数相当小,但仍不是一个好的解决方案。
有什么想法吗?
只需调用:
something.OrderBy(r => Guid.NewGuid()).Take(5)
OrderBy
假定排名函数是稳定的,但在使用随机生成器时并非如此。Linq to Entities会将其转换为SQL查询,可能会为同一实体获得不同的排名(只要您的查询使用了Include
)。这会导致实体在结果列表中重复出现。 - FrédéricGuid.NewGuid()
的Oracle等效项(意思是,LinqToSql或其他东西将其转换为NEWID()
,但没有人为Oracle编写相同的代码)。 - drzaus比较两个选项:
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();
}
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();
}
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
OrderBy(o => o.ID).Skip(skip).Take(5)
不会真正随机,这可能会成为性能瓶颈。 - Mike Mat.First()
”即可。我展示了一些其他答案的比较,但它们似乎不再存在,所以你的观点得到了双重验证。但是NewGuid
解决方案不会出现你描述的问题。 - drzausEF Core 6 中新增了一个函数:EF.Functions.Random()
something.OrderBy(r => EF.Functions.Random()).Take(5)
RAND()
函数,该函数对所有行只执行一次 - 这不会是随机的。请参见:https://dba.stackexchange.com/a/974/245938 接受的解决方案更好。 - Mr Patience你可以尝试以下方法:
public static String UdfGetRandomText()
{
using (Models.DbContextModel db = new Models.DbContextModel())
{
try
{
Entity.tblRandomTexts t = new Entity.tblRandomTexts();
t = db.tblRandomTexts.OrderBy(r => Guid.NewGuid()).First();
return (t.TextBuddy + Environment.NewLine + t.TextWriter);
}
catch (Exception ee)
{
return ee.Message;
}
}
}
假设您在EF中有一个类,如下所示,它创建了表。
public partial class tblRandomTexts
{
[Key]
public long TextRowID { get; set; }
[MaxLength(1500)]
public String TextBuddy { get; set; }
[MaxLength(100)]
public String TextWriter { get; set; }
}