EF Code First: Як отримати випадкові рядки


82

Як я можу побудувати запит, де б я отримував випадкові рядки?

Якби я писав це в SQL, то я б упорядкував newid () і відрубав б кількість рядків зверху. У будь-якому випадку зробити це спочатку у коді EF?

Я спробував створити запит, який використовує newid (), і виконати його за допомогою DbSet.SqlQuery (). Хоча це працює, це не найчистіші рішення.

Крім того, спробував отримати всі рядки та відсортувати їх за новим посібником. Незважаючи на те, що кількість рядів досить мала, це все ще не є гарним рішенням.

Будь-які ідеї?



Відповіді:


164

Просто зателефонуйте:

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

привіт, це чудово працює, але чи буде це швидко, коли таблиця має більше рядків, я розмістив тут
Shaiju T

3
Дивіться це питання , воно, на жаль, зламане. Схоже, OrderByфункція ранжирування вважається стабільною, що не є випадком із випадковим генератором. Linq to entity перекладе це на запит sql, який може отримати різний рейтинг для тієї самої сутності (як тільки ваші запити використовують Include). Тоді це призводить до того, що сутність дублюється у списку результатів.
Фредерік

1
Не впевнений, що я довіряю цьому для завдань, що вимагають залізного набору випадкових рядків - напевно, я б пішов із stackoverflow.com/a/654910/12484 або stackoverflow.com/a/648247/12484 - але цей простий підхід працював чудово для моєї потреби, що вимагало одного псевдовипадкового рядка для функції, яка не стосується клієнтів. +1.
Джон Шнайдер,

@Toolkit, мабуть, не такий дивний, якщо Entity не має еквівалента Oracle Guid.NewGuid()(мається на увазі, LinqToSql чи що інше, що перетворює це, NEWID()але ніхто не запрограмував те саме для Oracle).
drzaus

Чи ефективний такий підхід? Я ще десь виявив, що цей метод не рекомендується - для певної оцінки продуктивності.
Мохаммед Нурелдін

40

Порівняння двох варіантів:


Пропустити (випадкова кількість рядків)

Метод

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
Дякую за порівняння, це справді допомагає
Haobo

Це правильна відповідь. Позначена відповідь не рекомендується, оскільки це може спричинити деякі проблеми з продуктивністю.
Яків,

1
У запитанні зазначено "рядки" у множині, як би ви застосували своє рішення до цього? Мені здається, що мені доведеться виконувати один і той же SQL кілька разів, оскільки OrderBy(o => o.ID).Skip(skip).Take(5)це не буде насправді випадковим, що може стати вузьким місцем у роботі.
Mike Mat

@MikeMat Просто видаліть " .First()". Я представляв порівняння між деякими іншими побаченими відповідями, які більше не з’являються, тому ваша думка підтверджена вдвічі. Але NewGuidрішення не матиме проблеми, яку ви описуєте.
drzaus
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.