Linq : 조건부로 where 절에 조건 추가


103

이와 같은 쿼리가 있습니다.

(from u in DataContext.Users
       where u.Division == strUserDiv 
       && u.Age > 18
       && u.Height > strHeightinFeet  
       select new DTO_UserMaster
       {
         Prop1 = u.Name,
       }).ToList();

이 쿼리를 실행하는 메서드에 해당 조건이 제공되었는지 여부에 따라 연령, 신장과 같은 다양한 조건을 추가하고 싶습니다. 모든 조건에는 사용자 부문이 포함됩니다. 나이가 제공된 경우 쿼리에 추가하고 싶습니다. 마찬가지로 높이가 제공된 경우에도 추가하고 싶습니다.

이것이 SQL 쿼리를 사용하여 수행된다면 문자열 작성기를 사용하여 주 strSQL 쿼리에 추가했을 것입니다. 그러나 여기 Linq에서는 각 IF 블록에 추가 조건이있는 동일한 쿼리를 세 번 작성하는 IF 조건 만 사용할 수 있습니다. 이 작업을 수행하는 더 좋은 방법이 있습니까?

답변:


182

호출하지 않고 ToList()DTO 유형에 대한 최종 매핑을 수행하는 경우 Where계속해서 절을 추가 하고 마지막에 결과를 작성할 수 있습니다 .

var query = from u in DataContext.Users
   where u.Division == strUserDiv 
   && u.Age > 18
   && u.Height > strHeightinFeet
   select u;

if (useAge)
   query = query.Where(u => u.Age > age);

if (useHeight)
   query = query.Where(u => u.Height > strHeightinFeet);

// Build the results at the end
var results = query.Select(u => new DTO_UserMaster
   {
     Prop1 = u.Name,
   }).ToList();

이렇게하면 여전히 데이터베이스에 대한 단일 호출 만 발생하며 이는 한 번의 패스로 쿼리를 작성하는 것만 큼 효율적입니다.


1
"var query = .."문에 모든 where 조건을 입력해야합니까?
user20358

4
후속 Where 조건은 OR 또는 AND?
Vi100 2015

4
vi100 @ 그들은 그렇게, 추가 필터하고 있습니다
리드 Copsey

단순함에 감사드립니다! 위에서 훨씬 더 읽을 때 나는 20 + 라인 LINQ 쿼리를보고 너무 아프다
justanotherdev

이 오류가 발생하는 이유LINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Ali Umair

19

나는 일반적으로 메소드 체인을 사용하지만 동일한 문제가 있습니다. 그리고 여기 내가 사용하는 확장이 있습니다.

public static IQueryable<T> ConditionalWhere<T>(
        this IQueryable<T> source, 
        Func<bool> condition,
        Expression<Func<T, bool>> predicate)
    {
        if (condition())
        {
            return source.Where(predicate);
        }

        return source;
    }

체인 끊김을 방지하는 데 도움이됩니다. 또한 동일 ConditionalOrderBy하고 ConditionalOrderByDescending도움이됩니다.


도움이되지만 사용중인 모습의 예를 추가해 주시겠습니까?
Suncat2000 2016

1
다음과 같아야합니다. var fruits = await db.Fruits .ConditionalWhere (() => color! = null, f => f.Color == color) .ConditionalWhere (() => ripe! = null, f => f .Ripe == 익은) .ToListAsync ();
Yuriy Granovskiy 2016

4
잘 작동합니다! 감사! 또한 조건에 대한 오버로드를 함수 대신 간단한 부울 값으로 만들어 대리자가 불필요한 복잡성을 추가하는 위치를보다 직관적으로 만들었습니다. 지금은이 확장 방법을 자주 사용하고 있으며 귀하의 솔루션에 감사드립니다.
Suncat2000 2005

18

하나의 옵션.

bool? age = null

(from u in DataContext.Users
           where u.Division == strUserDiv 
           && (age == null || (age != null && u.Age > age.Value))
           && u.Height > strHeightinFeet  
           select new DTO_UserMaster
           {
             Prop1 = u.Name,
           }).ToList();

또는 linq의 메소드 구문으로 전환하고 if 조건을 사용하여 표현식을 where 절에 첨부 할 수 있습니다.


3

단순히 where 절에서 사용하고 있습니다.

    public IList<ent_para> getList(ent_para para){
     db.table1.Where(w=>(para.abc!=""?w.para==para.abc:true==true) && (para.xyz!=""?w.xyz==para.xyz:true==true)).ToList();
}

3

특정 조건에 따라 where 조건을 추가하십시오 ...

from u in DataContext.Users
where u.Division == strUserDiv 
&& u.Age != null ? u.Age > 18 : 1== 1
&& u.Height != null ? u.Height > 18 : 1== 1
&& u.Height != null ? u.Height > 18 : 1== 1
 select new DTO_UserMaster
       {
         Prop1 = u.Name,
       }).ToList();

2

비슷한 작업을 수행하는 코드는 다음과 같습니다. 이것은 내 WCF SOAP 웹 서비스 API의 메서드입니다.

    public FruitListResponse GetFruits(string color, bool? ripe)
    {
        try
        {
            FruitContext db = new FruitContext();
            var query = db.Fruits.Select(f => f);
            if (color != null)
            {
                query = query.Where(f => f.Color == color);
            }
            if (ripe != null)
            {
                query = query.Where(f => f.Ripe == ripe);
            }
            return new FruitListResponse
            {
                Result = query.Select(f => new Fruit { Id = f.FruitId, Name = f.Name }).ToList()
            };
        }
        catch (Exception e)
        {
            return new FruitListResponse { ErrorMessage = e.Message };
        }
    }

기본 쿼리는 Select(f => f)기본적으로 모든 것을 의미하며 Where절이 선택적으로 첨부됩니다. 마지막 Select은 선택 사항입니다. 데이터베이스 행 개체를 결과 "Fruit"개체로 변환하는 데 사용합니다.


0

다음 매개 변수를 가정하면,

Int? Age = 18;

간단하게 사용 &&||조건 연산자 우리는 다른 버전을 가질 수 있습니다.

(from u in DataContext.Users
where u.Division == strUserDiv 
    && (Age == null || u.Age > Age)
    && (Param1 == null || u.param1 == Param1)
    && u.Height > strHeightinFeet
select new DTO_UserMaster
{
    Prop1 = u.Name,
}).ToList();

Param1과 마찬가지로 검색 조건에 대해 여러 매개 변수를 추가 할 수 있습니다.


0

나는 방금 다른 것을 찾고 있지만 람다 버전을 던질 것이라고 생각했습니다.

먼저 데이터 영역에 매개 변수를 전달하기 위해 다음과 같은 클래스를 생성합니다.

   public class SearchParameters() {
       public int? Age {get; set;}
       public string Division {get;set;}
       etc
    }

그런 다음 데이터 영역에서 다음과 같습니다.

public IQueryable<User> SearchUsers(SearchParameters params) 
{
    var query = Context.Users;
    if (params.Age.HasValue)
    {
         query = query.Where(u => u.Age == params.Age.Value);
    }
    if (!string.IsNullOrEmpty(params.Division)
    {
        query = query.Where(u => u.Division == params.Division);
    }
    etc
    return query;
}

쿼리를 구체화하는 위치는 귀하에게 달려 있습니다. 앱과 데이터 사이에 db 관련 표현을 db-agnostic으로 변환하는 레이어가있을 수 있습니다 (여러 데이터 소스를 쿼리 할 수 ​​있음). 예를 들어 해당 계층은 이러한 소스에서 여러 유형의 쿼리 가능 항목을 가져 와서 공통 POCO 표현에 매핑 할 수 있습니다.


죄송합니다. John Henckel의 답변을 보지 못했습니다. 같은 생각.
스콧 피터슨

0

여기 에서 위의 허용 된 답변에 추가하기 위해 조인에 대해 동적 검색을 수행하는 경우 초기 linq 쿼리에서 두 테이블 (t1, t2)이있는 새 개체를 반환하여 개별적으로 액세스하여 조건부 작업을 수행 할 수 있습니다. 검색.

var query = from t1 in _context.Table1
            join t2 in _context.Table2 on t1.Table1Id equals t2.Table1IdId
            select new { t1, t2 };

        if (!string.IsNullOrEmpty(searchProperty1))
        {
            query = query.Where(collection => collection.t1.TableColumn == searchProperty1);
        }
        if (!string.IsNullOrEmpty(searchProperty2))
        {
            query = query.Where(collection => collection.t2.TableColumn == searchProperty2);
        }
        ....etc.

두 테이블을 조인하고 테이블 중 하나에서 특정 열을 쿼리하는 것과 관련하여 여기 에서 찾고 있던 대답을 얻었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.