/// <summary> /// Applies filtering to the IQueryable provided. /// </summary> /// <param name="query">The IQueryable that is to be filtered.</param> /// <param name="filteringForm">The filtering form.</param> /// <returns>A filtered IQueryable.</returns> public virtual IQueryable <TEntity> ApplyWhere(IQueryable <TEntity> query, IFilterForm filteringForm) { var term = filteringForm.GetTerm(); var words = GetWords(term); if (_getApplyWhere != null && term != null) { var applyWhere = _getApplyWhere(term); query = applyWhere(query); } // create predicate1 (word expressions) Expression <Func <TEntity, bool> > predicate1 = null; if (_getFreeWordPredicate != null) { foreach (var word in words) { predicate1 = AddExpression(predicate1, _getFreeWordPredicate(word), WordCombiner == WordSearchCombiner.And ? ExpressionType.AndAlso : ExpressionType.OrElse); } } // create predicate2 (sentence expression) Expression <Func <TEntity, bool> > predicate2 = null; if (_getFreeSentencePredicate != null && term != null) { predicate2 = _getFreeSentencePredicate(term); } // create predicate1 OR predicate2 as currentBody Expression <Func <TEntity, bool> > textPredicate = null; if (predicate1 != null && predicate2 != null) { textPredicate = predicate1.Or(predicate2); } else if (predicate1 != null) { textPredicate = predicate1; } else if (predicate2 != null) { textPredicate = predicate2; } var localizations = GetLocalizationDictionary(); Expression <Func <TEntity, bool> > keywordPredicate = null; for (int i = 0; i < words.Length; i++) { for (int j = i; j < words.Length; j++) { // from i to j var word = string.Join(" ", words, i, j - i + 1); Expression <Func <TEntity, bool> > predicate; if (_predefinedPredicates.TryGetValue(word, out predicate)) { keywordPredicate = AddExpression(keywordPredicate, predicate, ExpressionType.AndAlso); } Expression <Func <TEntity, bool> > localizedPredicate; if (localizations.TryGetValue(word, out localizedPredicate)) { keywordPredicate = AddExpression(keywordPredicate, localizedPredicate, ExpressionType.AndAlso); } } } // create textPredicate OR keywordPredicate as currentBody Expression <Func <TEntity, bool> > currentBody = null; if (textPredicate != null && keywordPredicate != null) { currentBody = textPredicate.Or(keywordPredicate); } else if (textPredicate != null) { currentBody = textPredicate; } else if (keywordPredicate != null) { currentBody = keywordPredicate; } Expression <Func <TEntity, bool> > parameterPredicate = null; var parameters = filteringForm.GetAdditionalFilters(); if (parameters != null) { foreach (var propertyComparison in parameters) { var comparisonType = propertyComparison.GetComparisonType(); var memberAccess = propertyComparison.GetMemberAccess(_parameter); var memberAccessor = memberAccess.MemberAccessor; var propertyType = memberAccess.MemberType; var unwrappedPropertyType = propertyType.GetTypeInfo().IsGenericType&& propertyType.GetGenericTypeDefinition() == typeof(Nullable <>) ? propertyType.GetTypeInfo().GetGenericArguments()[0] : propertyType; var propertyValue = propertyComparison.GetValue(); object convertedPropertyValue; if (propertyValue is string && (memberAccessor.Type == typeof(Guid) || memberAccessor.Type == typeof(Guid? ))) { convertedPropertyValue = Guid.Parse((string)propertyValue); } else { convertedPropertyValue = Convert.ChangeType(propertyValue, memberAccessor.Type); } var parameterizedPropertyValue = ExpressionHelper.WrappedConstant(memberAccessor.Type, convertedPropertyValue); Expression left = null; switch (comparisonType) { case ComparisonType.Equal: left = Expression.Equal(memberAccessor, parameterizedPropertyValue); break; case ComparisonType.GreaterThan: left = Expression.GreaterThan(memberAccessor, parameterizedPropertyValue); break; case ComparisonType.GreaterThanOrEqual: left = Expression.GreaterThanOrEqual(memberAccessor, parameterizedPropertyValue); break; case ComparisonType.LessThan: left = Expression.LessThan(memberAccessor, parameterizedPropertyValue); break; case ComparisonType.LessThanOrEqual: left = Expression.LessThanOrEqual(memberAccessor, parameterizedPropertyValue); break; case ComparisonType.StartsWith: left = Expression.Call(memberAccessor, StartsWith, parameterizedPropertyValue); break; case ComparisonType.Contains: left = Expression.Call(memberAccessor, Contains, parameterizedPropertyValue); break; default: throw new InvalidOperationException($"Invalid comparison type '{comparisonType}'."); } parameterPredicate = AddExpression( parameterPredicate, Expression.Lambda <Func <TEntity, bool> >(left, _parameter), ExpressionType.AndAlso); } } // combine with current body as needed if (currentBody != null && parameterPredicate != null) { currentBody = currentBody.And(parameterPredicate); } else if (parameterPredicate != null) { currentBody = parameterPredicate; } if (currentBody != null) { return(query.Where(currentBody)); } else { return(query); } }