EF 코드 우선 : 임의의 행을 얻는 방법


82

임의의 행을 검색하는 쿼리를 어떻게 작성할 수 있습니까?

SQL로 작성하면 newid ()에 의해 주문하고 상단에서 n 개의 행을 잘라냅니다. 어쨌든 EF 코드에서 이것을 먼저 수행합니까?

newid ()를 사용하는 쿼리를 만들고 DbSet.SqlQuery ()를 사용하여 실행하려고했습니다. 작동하는 동안 가장 깨끗한 솔루션은 아닙니다.

또한 모든 행을 검색하고 새 GUID로 정렬했습니다. 행 수가 상당히 적지 만 여전히 좋은 솔루션은 아닙니다.

어떤 아이디어?



답변:


164

전화 :

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

안녕하세요 제가 질문을 게시, 그것은 잘 작동하지만 표 이상의 행이있는 경우이 빨리 될 것입니다 여기에
Shaiju T

3
이 질문을 참조하십시오 . 불행히도 고장났습니다. OrderBy순위 함수가 안정적이라고 가정하는 것처럼 보이지만 임의 생성기에서는 그렇지 않습니다. Linq to entity는이를 동일한 엔티티에 대해 다른 순위를 얻을 수있는 SQL 쿼리로 변환합니다 (쿼리가를 사용하는 즉시 Include). 그런 다음 엔터티가 결과 목록에 복제됩니다.
Frédéric

1
아마로 가고 싶어 - 확실하지 난 임의 행의 엄격한 세트를 필요로하는 작업이 믿을 것 stackoverflow.com/a/654910/12484 또는 stackoverflow.com/a/648247/12484 대신에 -하지만이 간단한 방법은 비 고객 대면 기능에 대해 단일 의사 랜덤 행을 요구하는 내 필요에 맞게 잘 작동했습니다. +1.
Jon Schneider

Entity에 Oracle에 해당하는 Guid.NewGuid()(LinqToSql 또는 무엇을 의미 NEWID()하지만 Oracle에 대해 동일하게 프로그래밍 한 사람 이없는 경우) @Toolkit은 아마도 그렇게 이상하지 않을 것 입니다.
drzaus

이 접근 방식이 효율적입니까? 다른 곳에서이 방법은 성능을 고려하여 권장하지 않는다는 것을 발견했습니다.
Mohammed Noureldin

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;

Guid

방법

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

정답입니다. 표시된 답변은 성능 문제를 일으킬 수 있으므로 권장하지 않습니다.
Jacob

1
질문은 복수형으로 "행"을 말합니다. 솔루션을 어떻게 적용 하시겠습니까? 나에게는 동일한 SQL을 여러 번 실행해야 할 것 같습니다. 왜냐하면 OrderBy(o => o.ID).Skip(skip).Take(5)실제로 무작위가 아니기 때문에 성능에 병목이 될 수 있기 때문 입니다.
Mike Mat

@MikeMat " .First()"를 제거하십시오 . 더 이상 나타나지 않는 다른 답변과 비교하여 귀하의 요점이 이중으로 검증되었습니다. 그러나 NewGuid솔루션에는 설명하는 문제가 없습니다.
drzaus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.