IT

linq를 사용하여 ID 목록을 기반으로 여러 레코드 선택

lottoking 2020. 8. 11. 07:37
반응형

linq를 사용하여 ID 목록을 기반으로 여러 레코드 선택


UserProfile테이블 의 ID가 포함 된 목록이 있습니다. 어떻게 내가 모두를 선택할 수 있습니다. UserProfiles나는에있어 아이디의 목록을 기반으로 var사용 LINQ합니까?

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(......);

바로 여기에 생겼습니다. for 루프 등을 사용 하여이 작업을 수행 할 수 있습니다.하지만 LINQ.


그것을 위해 사용할 수 있습니다 . 실제로 을 생성하려고 할 때 약간 거꾸로 느껴지 지만 이렇게해야합니다.Contains()IN

var userProfiles = _dataContext.UserProfile
                               .Where(t => idList.Contains(t.Id));

또한 각 UserProfile레코드에 int Id필드 존재 가정 합니다. 일치하는 경우 그에 따라 조정해야합니다.


.Where .Contains를 및 솔루션은 O (N 제곱)의 결과를 가공합니다. Simple .Join은 훨씬 더 나은 성능을 가져옵니다 (해싱으로 인해 O (N)에 가까움). 따라서 올바른 코드는 다음과 가변적입니다.

_dataContext.UserProfile.Join(idList, up => up.ID, id => id, (up, id) => up);

그리고 이제 측정 결과입니다. 100,000 개의 UserProfile과 100,000 개의 ID가 생성되었습니다. Join은 32ms, .Where with .Contains는 2 분 19 초가 걸렸습니다! 이 테스트에서 내 전시를 증명하기 위해 순수 IEnumerable을 사용했습니다. IEnumerable 대신 List를 사용하면 .Where 및 .Contains가 더 빠 사용합니다. 어쨌든 그 차이는 중요합니다. 가장 빠른 .Where .Contains는 Set <>입니다. 모든 것은 .Contains에 대한 기본 콜레 션의 모든 것이 달려 있습니다. 봐이 게시물 아래 에있는 내 테스트 샘플에 복잡성. LINQ에서 배울 수 있습니다.

    private static void Main(string[] args)
    {
        var userProfiles = GenerateUserProfiles();
        var idList = GenerateIds();
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        userProfiles.Join(idList, up => up.ID, id => id, (up, id) => up).ToArray();
        Console.WriteLine("Elapsed .Join time: {0}", stopWatch.Elapsed);
        stopWatch.Restart();
        userProfiles.Where(up => idList.Contains(up.ID)).ToArray();
        Console.WriteLine("Elapsed .Where .Contains time: {0}", stopWatch.Elapsed);
        Console.ReadLine();
    }

    private static IEnumerable<int> GenerateIds()
    {
       // var result = new List<int>();
        for (int i = 100000; i > 0; i--)
        {
            yield return i;
        }
    }

    private static IEnumerable<UserProfile> GenerateUserProfiles()
    {
        for (int i = 0; i < 100000; i++)
        {
            yield return new UserProfile {ID = i};
        }
    }

콘솔 출력 :

경과. 가입 시간 : 00 : 00 : 00.0322546

경과. 어디. 시간 포함 : 00 : 02 : 19.4072107


좋은 대답이 중요한 한 가지를 잊지 않고 . 다른 결과를 제공합니다!

  var idList = new int[1, 2, 2, 2, 2]; // same user is selected 4 times
  var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e)).ToList();

이것은 DB에서 2 개의 행을 반환 할 것입니다 (사용자의 고유 한 정렬 목록을 원하는 경우입니다).

그러나 대부분의 경우 정렬되지 않은 결과 목록을 원할 수 있습니다. 항상 SQL 쿼리에 대해 생각해야합니다. 진행 상황을 비용으로 eshop 쇼핑 카트의 예를 참조하십시오.

  var priceListIDs = new int[1, 2, 2, 2, 2]; // user has bought 4 times item ID 2
  var shoppingCart = _dataContext.ShoppingCart
                     .Join(priceListIDs, sc => sc.PriceListID, pli => pli, (sc, pli) => sc)
                     .ToList();

그러면 DB에서 5 개의 결과 가 반환 됩니다. 이 경우 'contains'를 사용하는 것은 잘못된 것입니다.


간단해야합니다. 이 시도 :

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e));

참고 URL : https://stackoverflow.com/questions/16824510/select-multiple-records-based-on-list-of-ids-with-linq

반응형