[.net] Linq- 엔티티-SQL“IN”절

T-SQL에서는 다음과 같은 쿼리를 가질 수 있습니다.

SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")

LINQ to Entities 쿼리에서 어떻게 복제합니까? 가능합니까?



답변

당신이 생각하는 방식으로 머리를 켜야합니다. 사전 정의 된 적용 가능한 사용자 권한 세트에서 현재 항목의 사용자 권한을 찾기 위해 “입력”을 수행하는 대신 현재 항목의 해당 값이 포함되어 있는지 사전 정의 된 사용자 권한 세트를 요구합니다. 이것은 .NET의 일반 목록에서 항목을 찾는 것과 정확히 같은 방법입니다.

LINQ를 사용하여이 작업을 수행하는 방법에는 두 가지가 있습니다. 하나는 쿼리 구문을 사용하고 다른 하나는 메서드 구문을 사용합니다. 본질적으로 그것들은 동일하며 당신의 선호에 따라 상호 교환 가능하게 사용될 수 있습니다 :

쿼리 구문 :

var selected = from u in users
               where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
               select u

foreach(user u in selected)
{
    //Do your stuff on each selected user;
}

방법 구문 :

var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));

foreach(user u in selected)
{
    //Do stuff on each selected user;
}

변수를 할당하는 대신 다음과 같은 익명 호출을 통해 foreach를 수행 할 수 있기 때문에이 인스턴스에서 개인적으로 선호하는 방법은 구문입니다.

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

문법적으로 이것은 더 복잡해 보이며 실제로 무슨 일이 일어나고 있는지 파악하기 위해 람다 식 또는 대리자의 개념을 이해해야하지만, 알 수 있듯이 이것은 코드를 상당량 압축합니다.

그것은 모두 코딩 스타일과 선호도에 달려 있습니다. 내 세 가지 예제 모두 약간 다르게 똑같은 일을합니다.

다른 방법으로는 LINQ를 사용하지 않고 “where”를 “FindAll”로 바꾸는 동일한 방법 구문을 사용하고 동일한 결과를 얻을 수 있습니다.이 결과는 .NET 2.0에서도 작동합니다.

foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}


답변

이것은 당신의 목적으로 충분할 것입니다. 두 컬렉션을 비교하고 한 컬렉션에 다른 컬렉션의 값과 일치하는 값이 있는지 확인합니다.

fea_Features.Where(s => selectedFeatures.Contains(s.feaId))


답변

VS2008 / .net 3.5를 사용하는 경우 Alex James의 팁 # 8을 참조하십시오.
http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style)을 -queries-using-linq-to-entities.aspx

그렇지 않으면 array.Contains (someEntity.Member) 메소드를 사용하십시오.


답변

이 맥락에서 Inner Join으로갑니다. 포함을 사용하면 일치하는 항목이 하나만 있음에도 불구하고 6 번 반복합니다.

var desiredNames = new[] { "Pankaj", "Garg" };

var people = new[]
{
    new { FirstName="Pankaj", Surname="Garg" },
    new { FirstName="Marc", Surname="Gravell" },
    new { FirstName="Jeff", Surname="Atwood" }
};

var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered  select p.FirstName).ToList(); 

포함의 단점

두 개의 목록 객체가 있다고 가정합니다.

List 1      List 2
  1           12
  2            7
  3            8
  4           98
  5            9
  6           10
  7            6

포함을 사용하면 목록 2에서 각 목록 1 항목을 검색하여 반복이 49 회 발생한다는 것을 의미합니다 !!!


답변

이것은 LINQ 확장 메소드를 직접 사용하여 in 절을 확인할 수있는 가능한 방법 일 수 있습니다.

var result = _db.Companies.Where(c => _db.CurrentSessionVariableDetails.Select(s => s.CompanyId).Contains(c.Id)).ToList();


답변

또한 Entity Data Model 에 대해 SQL-IN과 비슷한 것을 쿼리하려고했습니다 . 내 접근 방식은 큰 OR 식을 작성하는 문자열 작성기입니다. 정말 못 생겼지 만 지금 당장 갈 수있는 유일한 방법 인 것 같습니다.

이제 다음과 같이 보입니다.

Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
    while(productIds.Count > 0)
    {
        sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
          entities.Products.Name, productIds.Dequeue());
    }
}

이 컨텍스트에서 GUID 작업 : 위에서 볼 수 있듯이 쿼리 문자열 조각에서 GUID 앞에 “GUID”라는 단어가 항상 있습니다. 이것을 추가하지 않으면 ObjectQuery<T>.Where다음 예외가 발생합니다.

인수 유형 ‘Edm.Guid’및 ‘Edm.String’은이 작업과 호환되지 않습니다. 거의 식 6, 열 14와 같습니다.

MSDN 포럼에서 이것을 발견하면 염두에 두는 것이 도움이 될 수 있습니다.

마티아스

… 모든 것이 더 나아질 때 .NET 및 Entity Framework의 다음 버전을 기대합니다. 🙂


답변

BenAlabaster의 대안 대안

우선 다음과 같이 쿼리를 다시 작성할 수 있습니다.

var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" ||
              Users.User_Rights == "Limited"
        select Users;

확실히 이것은 더 ‘말랑 말랑한’이고 쓰는 것이 고통 스럽지만 모두 동일하게 작동합니다.

따라서 이런 종류의 LINQ 표현을 쉽게 만들 수있는 유틸리티 방법이 있다면 우리는 사업을 할 것입니다.

유틸리티 메소드를 사용하면 다음과 같이 작성할 수 있습니다.

var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);

이렇게하면 다음과 같은 효과가있는 표현식이 작성됩니다.

var matches = from p in ctx.People
        where names.Contains(p.User_Rights)
        select p;

그러나 더 중요한 것은 실제로 .NET 3.5 SP1에 대해 작동합니다.

이를 가능하게하는 배관 기능은 다음과 같습니다.

public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
        Expression<Func<TElement, TValue>> valueSelector,
        IEnumerable<TValue> values
    )
{
    if (null == valueSelector)
        throw new ArgumentNullException("valueSelector");

    if (null == values)
        throw new ArgumentNullException("values");

    ParameterExpression p = valueSelector.Parameters.Single();

    if (!values.Any())
        return e => false;

    var equals = values.Select(value =>
        (Expression)Expression.Equal(
             valueSelector.Body,
             Expression.Constant(
                 value,
                 typeof(TValue)
             )
        )
    );
   var body = equals.Aggregate<Expression>(
            (accumulate, equal) => Expression.Or(accumulate, equal)
    );

   return Expression.Lambda<Func<TElement, bool>>(body, p);
}

나는 본질적으로 valueSelector (예 : p => p.User_Rights)를 사용하여 모든 값에 대한 술어 표현식을 작성하고 그 술어를 함께 사용하여 완전한 표현식을 작성한다고 말하는 것 외에는이 방법을 설명하려고하지 않습니다. 술부

출처 : http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx