2017-12-04 14 views
2

User, FilterFilterEntry의 클래스가있는 모델이 있습니다.엔터티 프레임 워크 코어의 필터가 포함 된 복잡한 쿼리

class Filter 
{ 
    public List<FilterEntry> Inclusions { get; set; } 
    public List<FilterEntry> Exclusions { get; set; } 
} 

public class FilterEntry 
{ 
    public string Name { get; set; } 
    public int? Age { get; set; } 
} 

public class User 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

Filter는 DB에 지속 된 필터, 당신은 필터의 정의처럼 볼 수 있습니다. 필터를 정의하는 하나 이상의 FilterEntries을 포함합니다. 포함 사항 및 제외 사항은 필터에 적용되는 제한 사항입니다.

예 :

var filter = new Filter 
    { 
     Inclusions = new[] { new FilterEntry { Age = 33 } }, 
     Exclusions = new[] { new FilterEntry { Name = "John" }, new FilterEntry { Name = "Peter" } }, 
    }; 

이 "존"또는 "베드로"라고하는 사람을 제외하고, 33 세 사람을 대표하는 Filter 정의합니다. 따라서이 필터가 사용자에게 적용되면 Johns와 Peters를 제외한 33 인 모든 사용자를 반환해야합니다.

이제 문제가 발생했습니다. Entity Framework를 사용하여 쿼리를 만들려면 어떻게합니까? 필터는 사용자를 반환합니다.

저는 시작하는 방법조차 모릅니다! 내가 가지고있는 것 :

Filter filter = dbContext.Filters.First(x => x.FilterId == filterId); 
var filteredUsers = from u in dbContext.Users 
    where ... // user is any of the in filter.Inclusions 
    where ... // user is not in any of the filter.Exclusions 
    select u; 

주의 사항 Filter와 FilterEntry는 1-N 관계를 유지합니다. 코드를 단순화하기 위해 키를 생략했습니다.

+1

필터의 이름/나이가 항상 맞습니까? 아니면 다른 필터 요구 사항을 제외 했습니까? – gh9

+0

예, 간단히하기 위해 일부 필터를 제외 시켰습니다. 예를 들어, FilterEntry에 국가를 지정하면 네비게이션 속성이 포함되어 국가를 지정하면 포함/제외시킬 수 있습니다. FilterEntry의 속성에있는 null 값은 주어진 필터 필드가 설정되지 않았 음을 의미합니다. 예를 들어, FilterEntry는 모든 속성이 null이지만 Country는 국가 만 적용됨을 의미합니다. 그래서 Age가 nullable입니다. Null은 멤버에 대한 필터가 적용되는시기를 결정합니다. – SuperJMN

답변

3

동적 where 절을 만들려고하므로 PredicateBuilder을 권장합니다. 아래 코드를 테스트하지는 않았지만 같은 것을 원할 것입니다.

Filter filter = dbContext.Filters.First(x => x.FilterId == filterId); 

var pb = new PredicateBuilder<User>(); 

foreach(var inclusion in filter.Inclusions) 
{ 
    if(inclusion.Age.HasValue) 
    { 
     pb = pb.And(p => p.Age == inclusion.Age.Value); 
    } 
    if(!string.IsNullOrWhiteSpace(inclusion.Name)) 
    { 
     pb = pb.And(p => p.Name == inclusion.Name); 
    } 
} 

foreach(var exclusion in filter.Exclusions) 
{ 
    if(exclusion.Age.HasValue) 
    { 
     pb = pb.And(p => p.Age != exclusion.Age.Value); 
    } 
    if(!string.IsNullOrWhiteSpace(exclusion.Name)) 
    { 
     pb = pb.And(p => p.Name != exclusion.Name); 
    } 
} 

var filteredUsers = dbContext.Users.AsExpandable().Where(pb); 
+0

감사합니다. @Eric Lease. 국가를 포함/제외시키기 위해 회원국 회원을 FilterEntry에 포함 시키면 어떻게 될까요? 이것이 여전히 해결책일까요? 그리고 Couple.CountryOfBirth와 같이 중첩 된 필터가 있다면? – SuperJMN

+0

Eric, ASP.NET 코어 2에서 PredicateBuilder를 사용하려면 어떤 패키지를 설치해야합니까? – SuperJMN

+0

찾았습니다. LinqKit입니다 .Microsoft.EntityFrameworkCore – SuperJMN

2

이와 비슷한 동적 필터를 지정할 수있는 시나리오가있었습니다. 나는 System.Linq.Dynamic.Core NuGet 패키지 (https://github.com/StefH/System.Linq.Dynamic.Core)를 사용하여 끝내었다. 이렇게하면 문자열 입력을 사용하여 Linq 쿼리를 실행할 수 있습니다. 그런 다음 Filter에서 Linq 표현식 트리를 작성하지 않고 where 절을 문자열로 구성하면됩니다.

public class Filter 
{ 
    public List<FilterEntry> Inclusions { get; set; } 
    public List<FilterEntry> Exclusions { get; set; } 

    public IQueryable<User> ApplyTo<User>(IQueryable<User> queryable) 
    { 
     // TODO: Dynamically build this string instead of hard-coding it. 
     //  You would probably iterate through Inclusions and Exclusions 
     //  appending to the where clause as you go. 
     var whereClause = "Age == @0 && Name != @1 && Name != @2"; 
     var params = new object[] { 33, "John", "Peter" }; 

     return queryable.Where(whereClause, params); 
    } 
} 

실용적인 해결책이 아니라는 것을 알고 있지만, 적어도 시작하기 좋은 곳을 제공합니다.