2016-07-03 7 views
1

먼저 EntityFramework 데이터베이스를 사용하는 REST WebAPI가 있습니다. 모든 코드는 EDMX 파일, 엔티티, 리포지토리 클래스 및 API 컨트롤러 등을 통해 생성됩니다. LinqKit PredicateBuilder/Linq로 변환되는 쿼리 문자열을 통해 조건을 추가 할 수있는 몇 가지 필터링 기능이 추가되었습니다. db를 치면 결과를 필터링하는 표현식 . Linq PredicateBuilder를 사용하여 문자열 검색 연결

e.g. /api/Users?FirstName_contains=Rog 

User.FirstName 멤버 '로저'모든 사용자를 반환합니다. 이는 PredicateBuilder을 사용하여 적절한 표현식을 동적으로 작성한 다음 DbSet에 대해 Where 절로 사용합니다. 예를 들어

: 이제

var fieldName = "FirstName"; 
var value = "Rog"; 

var stringContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); 

var parameter = Expression.Parameter(typeof(User), "m"); 
var fieldAccess = Expression.PropertyOrField(parameter, fieldName); 
var fieldType = typeof(User).GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).PropertyType; 

var expression = Expression.Lambda<Func<User, bool>>(Expression.Call(fieldAccess, stringContainsMethod, Expression.Constant(value, fieldType)) 
    , parameter) 

var andPredicate = PredicateBuilder.True<User>(); 
andPredicate = andPredicate.And(expression); 

var query = Db.Users 
    .AsQueryable() 
    .AsExpandable() 
    .Where(andPredicate); 

문제

. 클라이언트가 회원 구성에 따라 결과를 일치 시키길 원합니다.

e.g. /api/Users?api_search[FirstName,LastName]=Rog 

즉 '로저'의 경기에 대한 first name + last name 검색, 그래서 '로저 SM'을 검색하여 이름 = 로저 이름과 성 = 스미스에 대한 결과를 얻을 수 있습니다. 나는 유창하게 사용 DbSet를 조회 할 수 있었다면

그것과 같습니다

나는 선재 FirstName + " " + LastName 동적으로의 연결을 처리하는 predicate/linq 식을 만드는 고민하고 무엇
users.Where(u => (u.FirstName + " " + u.LastName).Contains("Rog")); 

.

+0

t-sql에 CONCAT 함수가 있지만 EF (특히 L2SQL) 기능이이 변환을 지원한다고 생각하지 않습니다. 먼저 .ToList()를 사용하여 모든 항목을 가져온 다음 메모리에서 Selection을 수행해야합니다. – DevilSuichiro

+0

흠 정말로? 내 여행에서 나는 위의 유창한 예제가'WHERE FirstName + '+ LastName LIKE'% Rog % ''의 T-SQL로 변환 될 것이라고 확신합니다. –

+0

왜 'u => u.FirstName.Contains (query) || u.LastName.Contains (query)'? – haim770

답변

1

PredicateBuilder 정말 여기에 필요하지 않습니다.

문자열 연결 표현은 EF에서 지원 string.Concat 메서드 호출을 사용하여 생성 할 수 있습니다

static Expression<Func<T, string>> GenerateConcat<T>(IEnumerable<string> propertyNames) 
{ 
    var parameter = Expression.Parameter(typeof(T), "e"); 
    // string.Concat(params string[] values) 
    var separator = Expression.Constant(" "); 
    var concatArgs = Expression.NewArrayInit(typeof(string), propertyNames 
     .SelectMany(name => new Expression[] { separator, Expression.PropertyOrField(parameter, name) }) 
     .Skip(1)); 
    var concatCall = Expression.Call(typeof(string).GetMethod("Concat", new[] { typeof(string[]) }), concatArgs); 
    return Expression.Lambda<Func<T, string>>(concatCall, parameter); 
} 

문자열은 술어가 간단한 string.Contains 메서드 호출에 의해 생성 할 수 있습니다 포함

static Expression<Func<T, bool>> GenerateContains<T>(Expression<Func<T, string>> member, string value) 
{ 
    var containsCall = Expression.Call(member.Body, "Contains", Type.EmptyTypes, Expression.Constant(value)); 
    return Expression.Lambda<Func<T, bool>>(containsCall, member.Parameters); 
} 

을 결합 귀하의 예와 함께 :

var predicate = GenerateContains(GenerateConcat<User>(new[] { "FirstName", "LastName" }), "Rog"); 
+0

감사합니다 이반 - 훌륭합니다. 나는 받아 들인 대답을 바꿨다. 그렇다. 당신이 옳다는 것은 정확한 람다 식을 만드는 것에 관한 질문 일 뿐이다. PredicateBuilder는 컬렉션에 대한 실행을 위해 다양한 표현식의 체인을 처리합니다. –

0

은 (나는 데이터베이스에 대해 그것을 테스트하지 않은 경우) 다음보십시오 :

public class User 
{ 
public string FirstName { get; set; } 
public string LastName { get; set;} 
} 
void Main() 
{ 
    List<User> users = new List<User> { 
          new User { FirstName = "john", LastName = "smith" }, 
          new User { FirstName = "siler", LastName = "johnston" } }; 
    string searchName = "ja smi"; 
    String[] terms = searchName.Split(' '); 
    var items = users.Where(x => terms.Any(y => x.FirstName.Contains(y)) 
           || terms.Any(y => x.LastName.Contains(y))); 
} 
+0

감사합니다. 용어를 분리하고 Any/Or 기반 검색을 수행하는 것이 연결을 성취 할 수없는 경우에 확실히 후퇴합니다. 이제는 그것에 대해 생각해 볼 때 결과가 좋을지 알아보기 위해 시도 할 것입니다. –

+0

기술적 인 측면에서 볼 때 비록 내 기능이 이미 가능할지라도 나는 이것을 앞으로 나아갈 길로 받아 들였습니다. '/ api/Users? or_firstName_contains = ja & or_firstName_contains = smi & or_lastName_contains = ja & or_lastName_contains = smi'입니다. 나는 Linq이 이미 규칙적인 유창성이나 질의 문법을 사용하기 때문에 가능할 것임을 안다. 그러나 이것은 현재 내가 줄을 잡아야한다. –