Commits

Luis Fernando committed ba8ae2a

More granular control over case-insensitive search, ValueResolvers can now be added to a single query.

Comments (0)

Files changed (30)

ExampleWebApplication/ExampleWebApplication.csproj

       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll</HintPath>
     </Reference>
-    <Reference Include="WebActivator, Version=1.5.1.0, Culture=neutral, processorArchitecture=MSIL">
+    <Reference Include="WebActivator, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\WebActivator.1.5.1\lib\net40\WebActivator.dll</HintPath>
+      <HintPath>..\packages\WebActivator.1.5.2\lib\net40\WebActivator.dll</HintPath>
     </Reference>
   </ItemGroup>
   <ItemGroup>

ExampleWebApplication/packages.config

   <package id="EntityFramework" version="5.0.0" targetFramework="net40" />
   <package id="EntityFrameworkProfiler" version="1.0.0.951" targetFramework="net40" />
   <package id="Iesi.Collections" version="3.3.2.4000" targetFramework="net40" />
-  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" />
+  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
   <package id="NHibernate" version="3.3.2.4000" targetFramework="net40" />
   <package id="NHibernateProfiler" version="2.0.13.0" targetFramework="net40" />
   <package id="TelerikMvcExtensions" version="2012.2.607" />
-  <package id="WebActivator" version="1.5.1" />
+  <package id="WebActivator" version="1.5.2" targetFramework="net40" />
 </packages>

TelerikMvcGridCustomBindingHelper.NHibernate/DynamicQuery/QueryOverDynamicWhereClause.cs

     {
         public QueryOverDynamicWhereClause() { }
 
-        public QueryOverDynamicWhereClause(FilterDescriptor filterDescriptor, bool queryUseCaseInsensitiveSearch, bool queryAcceptNullValuesWhenFiltering)
-            : base(filterDescriptor, queryUseCaseInsensitiveSearch, queryAcceptNullValuesWhenFiltering) { }
+        public QueryOverDynamicWhereClause(FilterDescriptor filterDescriptor, CaseInsensitive<TEntity> caseInsensitive, bool queryAcceptNullValuesWhenFiltering, ValueResolvers queryValueResolvers)
+            : base(filterDescriptor, caseInsensitive, queryAcceptNullValuesWhenFiltering, queryValueResolvers) { }
 
         private IProjection _propertyProjection;
         private IProjection PropertyProjection

TelerikMvcGridCustomBindingHelper.NHibernate/NHibernateGridCustomBindingHelper.cs

 
         #region Fluent API
 
+        public new NHibernateGridCustomBindingHelper<TEntity, TViewModel> AddValueResolver<TQueryValueResolver>(Expression<Func<TViewModel, object>> viewModelProperty) where TQueryValueResolver : class, IQueryValueResolver
+        {
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)base.AddValueResolver<TQueryValueResolver>(viewModelProperty);
+        }
+
+        public new NHibernateGridCustomBindingHelper<TEntity, TViewModel> AddValueResolver<TQueryValueResolver>() where TQueryValueResolver : class, IQueryValueResolver
+        {
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)base.AddValueResolver<TQueryValueResolver>();
+        }
+
+        public new NHibernateGridCustomBindingHelper<TEntity, TViewModel> AddValueResolver(IQueryValueResolver queryValueResolver)
+        {
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)base.AddValueResolver(queryValueResolver);
+        }
+
+        public new NHibernateGridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(bool useCaseInsensitiveSearchOnBothClientAndServerSide = true)
+        {
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)base.UseCaseInsensitiveSearch(useCaseInsensitiveSearchOnBothClientAndServerSide);
+        }
+
+        public new NHibernateGridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(Action<ICaseOptions<TEntity>> caseOptions)
+        {
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)base.UseCaseInsensitiveSearch(caseOptions);
+        }
+
         /// <summary>
         /// Adds a custom aggregate function.
         /// </summary>
         /// <returns>This same <see cref="NHibernateGridCustomBindingHelper{TEntity,TViewModel}"/>.</returns>
         public NHibernateGridCustomBindingHelper<TEntity, TViewModel> AddAggregateFunction<TAggregateFunction>(Expression<Func<TViewModel, object>> targetProperty) where TAggregateFunction : CustomAggregateFunction, new()
         {
-            return AddAggregateFunctionBase<TAggregateFunction>(targetProperty) as NHibernateGridCustomBindingHelper<TEntity, TViewModel>;
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)AddAggregateFunctionBase<TAggregateFunction>(targetProperty);
         }
 
         /// <summary>
         public NHibernateGridCustomBindingHelper<TEntity, TViewModel> AddAggregateFunction(Expression<Func<TViewModel, object>> targetProperty, Func<IQueryOver<TEntity>, IFutureValue<object>> queryOverfunction, Func<IQueryable<TEntity>, object> queryablefunction)
         {
             _queryOverExpressionCustomAggregateFunction = queryOverfunction;
-            return AddAggregateFunctionBase(targetProperty, queryablefunction) as NHibernateGridCustomBindingHelper<TEntity, TViewModel>;
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)AddAggregateFunctionBase(targetProperty, queryablefunction);
         }
 
         public NHibernateGridCustomBindingHelper<TEntity, TViewModel> AddAggregateFunction(Expression<Func<TViewModel, object>> targetProperty, Expression<Func<IQueryOver<TEntity, TEntity>, IFutureValue<object>>> queryOverfunction)
 
             var queryablefunction = PredicateConverter.TryConvert(queryOverfunction);
 
-            return AddAggregateFunctionBase(targetProperty, queryablefunction) as NHibernateGridCustomBindingHelper<TEntity, TViewModel>;
+            return (NHibernateGridCustomBindingHelper<TEntity, TViewModel>)AddAggregateFunctionBase(targetProperty, queryablefunction);
         }
 
         #endregion
                     else
                     {
                         var filter = (FilterDescriptor)filterDescriptor;
-                        var whereClause = new QueryOverDynamicWhereClause<TEntity, TViewModel>(filter, UseCaseInsensitiveSearchField, AcceptNullValuesWhenFilteringField);
+                        var whereClause = new QueryOverDynamicWhereClause<TEntity, TViewModel>(filter, CaseInsensitiveField, AcceptNullValuesWhenFilteringField, QueryValueResolvers);
 
                         if (logicalOperator == FilterCompositionLogicalOperator.And)
                         {

TelerikMvcGridCustomBindingHelper/BaseGridCustomBindingHelper.cs

         protected bool IgnoreGroupAggregatesField;
         protected Func<IQueryable<TEntity>, object> ExpressionCustomAggregateFunctionField;
         private Func<IQueryable<TViewModel>, object> _aggregateViewModelFunctionField;
-        protected bool UseCaseInsensitiveSearchField;
+        internal CaseInsensitive<TEntity> CaseInsensitiveField;
 
         #endregion
 
 
         #region Fluent API
 
-        public BaseGridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(bool useCaseInsensitiveSearch = true)
+        protected ValueResolvers QueryValueResolvers;
+
+        protected BaseGridCustomBindingHelper<TEntity, TViewModel> AddValueResolver<TQueryValueResolver>(Expression<Func<TViewModel, object>> viewModelProperty) where TQueryValueResolver : class, IQueryValueResolver
         {
-            UseCaseInsensitiveSearchField = useCaseInsensitiveSearch;
+            Contract.Expect(() => viewModelProperty).IsNotNull();
+
+            if (IsValidPropertyExpression(viewModelProperty) == false)
+                throw new NotSupportedException(string.Format("This expression is not supported: {0}", viewModelProperty));
+
+            var queryValueResolver = ObjectFactory<TQueryValueResolver>.Create();
+            queryValueResolver.SetTargetProperty(viewModelProperty.GetPropertyPath());
+
+            return AddValueResolver(queryValueResolver);
+        }
+
+        private static bool IsValidPropertyExpression(LambdaExpression expression)
+        {
+            var body = expression.Body;
+
+            if (body.NodeType == ExpressionType.Convert)
+            {
+                body = ((UnaryExpression)body).Operand;
+            }
+
+            return body.NodeType == ExpressionType.MemberAccess;
+        }
+
+        protected BaseGridCustomBindingHelper<TEntity, TViewModel> AddValueResolver<TQueryValueResolver>() where TQueryValueResolver : class, IQueryValueResolver
+        {
+            return AddValueResolver(ObjectFactory<TQueryValueResolver>.Create());
+        }
+
+        protected BaseGridCustomBindingHelper<TEntity, TViewModel> AddValueResolver(IQueryValueResolver queryValueResolver)
+        {
+            QueryValueResolvers = QueryValueResolvers ?? new ValueResolvers();
+
+            var valueResolverKey = ValueResolverKey.QueryKey(queryValueResolver);
+
+            var containsKey = QueryValueResolvers.ContainsKey(valueResolverKey);
+
+            while (containsKey)
+            {
+                IValueResolver vr;
+                containsKey = QueryValueResolvers.TryRemove(valueResolverKey, out vr);
+            }
+
+            var tryAdd = QueryValueResolvers.TryAdd(valueResolverKey, queryValueResolver);
+
+            Guard.If(tryAdd == false).Throw<ValueResolverRegistrationException>(queryValueResolver);
+
+            return this;
+        }
+
+        protected BaseGridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(bool useCaseInsensitiveSearchOnBothClientAndServerSide = true)
+        {
+            CaseInsensitiveField = new CaseInsensitive<TEntity>();
+            CaseInsensitiveField.BothClientAndServerSide(useCaseInsensitiveSearchOnBothClientAndServerSide);
+            return this;
+        }
+
+        protected BaseGridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(Action<ICaseOptions<TEntity>> caseOptions)
+        {
+            CaseInsensitiveField = new CaseInsensitive<TEntity>();
+            caseOptions(CaseInsensitiveField);
             return this;
         }
 

TelerikMvcGridCustomBindingHelper/CaseInsensitive.cs

+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace TelerikMvcGridCustomBindingHelper
+{
+    public interface IBaseCaseOptions
+    {
+        void ServerSideOnly();
+        void ClientSideOnly();
+        void BothClientAndServerSide(bool useCaseInsensitiveSearchOnBothClientAndServerSide = true);
+    }
+
+    public interface ICaseOptions<TEntity> : IBaseCaseOptions
+    {
+        new ICaseOptions<TEntity> ServerSideOnly();
+        new ICaseOptions<TEntity> ClientSideOnly();
+        ICaseOptions<TEntity> Ignore(Expression<Func<TEntity, object>> selector);
+        ICaseOptions<TEntity> Use(Expression<Func<TEntity, object>> selector);
+    }
+
+    internal class CaseInsensitive<TEntity> : ICaseOptions<TEntity>
+    {
+        private bool _isDefault = true;
+        public bool ShouldBeOnServerSide { get; private set; }
+        public bool ShouldBeOnClientSide { get; private set; }
+        internal readonly List<LambdaExpression> PropertiesToIgnore = new List<LambdaExpression>();
+        internal readonly List<LambdaExpression> PropertiesToUse = new List<LambdaExpression>();
+
+        public CaseInsensitive() { }
+
+        public CaseInsensitive(bool shouldBeOnServerSide, bool shouldBeOnClientSide)
+        {
+            ShouldBeOnServerSide = shouldBeOnServerSide;
+            ShouldBeOnClientSide = shouldBeOnClientSide;
+            _isDefault = false;
+        }
+
+        ICaseOptions<TEntity> ICaseOptions<TEntity>.ServerSideOnly()
+        {
+            ShouldBeOnServerSide = true;
+            ShouldBeOnClientSide = false;
+            _isDefault = false;
+            return this;
+        }
+
+        ICaseOptions<TEntity> ICaseOptions<TEntity>.ClientSideOnly()
+        {
+            ShouldBeOnClientSide = true;
+            ShouldBeOnServerSide = false;
+            _isDefault = false;
+            return this;
+        }
+
+        public void BothClientAndServerSide(bool useCaseInsensitiveSearchOnBothClientAndServerSide)
+        {
+            ((ICaseOptions<TEntity>)this).BothClientAndServerSide(useCaseInsensitiveSearchOnBothClientAndServerSide);
+        }
+
+        void IBaseCaseOptions.BothClientAndServerSide(bool useCaseInsensitiveSearchOnBothClientAndServerSide)
+        {
+            ShouldBeOnClientSide = ShouldBeOnServerSide = useCaseInsensitiveSearchOnBothClientAndServerSide;
+            _isDefault = false;
+        }
+
+        void IBaseCaseOptions.ClientSideOnly()
+        {
+            ((ICaseOptions<TEntity>)this).ClientSideOnly();
+        }
+
+        void IBaseCaseOptions.ServerSideOnly()
+        {
+            ((ICaseOptions<TEntity>)this).ServerSideOnly();
+        }
+
+        ICaseOptions<TEntity> ICaseOptions<TEntity>.Ignore(Expression<Func<TEntity, object>> selector)
+        {
+            PropertiesToIgnore.Add(selector);
+
+            if (_isDefault)
+            {
+                BothClientAndServerSide(true);
+            }
+
+            return this;
+        }
+
+        ICaseOptions<TEntity> ICaseOptions<TEntity>.Use(Expression<Func<TEntity, object>> selector)
+        {
+            PropertiesToUse.Add(selector);
+
+            if (_isDefault)
+            {
+                BothClientAndServerSide(true);
+            }
+
+            return this;
+        }
+
+        public void CopyFrom<TCaseInsensitiveEntity>(IBaseCaseOptions baseCaseOptions)
+        {
+            var opt = (CaseInsensitive<TCaseInsensitiveEntity>)baseCaseOptions;
+
+            if (opt == null)
+                return;
+
+            ShouldBeOnClientSide = opt.ShouldBeOnClientSide;
+            ShouldBeOnServerSide = opt.ShouldBeOnServerSide;
+
+            _isDefault = false;
+        }
+    }
+}

TelerikMvcGridCustomBindingHelper/DynamicQuery/BaseDynamicWhereClause.cs

         where TEntity : class
         where TViewModel : class
     {
-        private readonly bool _useCaseInsensitiveSearch;
+        private readonly CaseInsensitive<TEntity> _caseInsensitive;
         private readonly bool _queryAcceptNullValuesWhenFiltering;
+        private readonly ValueResolvers _queryValueResolvers;
         protected readonly FilterDescriptor InnerFilterDescriptor;
         protected readonly object ConvertedValue;
         public GridPropertyInfo GridPropertyInfo { get; private set; }
 
         protected BaseDynamicWhereClause() { }
 
-        protected BaseDynamicWhereClause(FilterDescriptor filterDescriptor, bool queryUseCaseInsensitiveSearch, bool queryAcceptNullValuesWhenFiltering)
+        protected BaseDynamicWhereClause(FilterDescriptor filterDescriptor, CaseInsensitive<TEntity> caseInsensitive, bool queryAcceptNullValuesWhenFiltering, ValueResolvers queryValueResolvers)
         {
+            _queryValueResolvers = queryValueResolvers;
             InnerFilterDescriptor = filterDescriptor;
             GridPropertyInfo = GetGridPropertyInfo(filterDescriptor.Member);
-            ConvertedValue = ConvertValue(filterDescriptor.Value);
+            ConvertedValue = ResolveValue(filterDescriptor.Value);
             _queryAcceptNullValuesWhenFiltering = queryAcceptNullValuesWhenFiltering;
-            _useCaseInsensitiveSearch = queryUseCaseInsensitiveSearch || GridModelMapper.ConfigurationObject.GlobalUseCaseInsensitiveSearch;
+
+            _caseInsensitive = new CaseInsensitive<TEntity>();
+
+            if (caseInsensitive != null)
+            {
+                _caseInsensitive = caseInsensitive;
+            }
+            else
+            {
+                _caseInsensitive.CopyFrom<object>(GridModelMapper.ConfigurationObject.GlobalCaseInsensitiveSearchOptions);
+            }
 
             InitializePredicate();
         }
             }
             else
             {
-                if (_useCaseInsensitiveSearch && (GridPropertyInfo.PropertyType == typeof(string) && ConvertedValue != null))
+                var shouldUseCaseSensitivity = ShouldUseCaseSensitivity();
+
+                var value = ConvertedValue;
+
+                if ((_caseInsensitive.ShouldBeOnClientSide && shouldUseCaseSensitivity) && (GridPropertyInfo.PropertyType == typeof(string) && ConvertedValue != null))
                 {
-                    predicate = BuildPredicateCaseInsensitive(((string)ConvertedValue).ToLowerInvariant());
+                    value = ((string)ConvertedValue).ToLower(GridModelMapper.ConfigurationObject.DefaultCulture);
+                }
+
+                if ((_caseInsensitive.ShouldBeOnServerSide && shouldUseCaseSensitivity) && (GridPropertyInfo.PropertyType == typeof(string) && value != null))
+                {
+                    predicate = BuildPredicateCaseInsensitive((string)value);
                 }
                 else
                 {
-                    predicate = BuildPredicateCaseSensitive(ConvertedValue);
+                    predicate = BuildPredicateCaseSensitive(value);
                 }
             }
 
             Predicate = OrElse(predicateThatAcceptNullValues, predicate);
         }
 
+        private bool ShouldUseCaseSensitivity()
+        {
+            var shouldIgnore = new PropertyPathVisitor();
+            foreach (var expression in _caseInsensitive.PropertiesToIgnore)
+            {
+                shouldIgnore.Visit(expression);
+            }
+
+            if (shouldIgnore.Properties.Any(p => p == GridPropertyInfo.PropertyPath))
+            {
+                return false;
+            }
+
+            var shouldUse = new PropertyPathVisitor();
+            foreach (var expression in _caseInsensitive.PropertiesToUse)
+            {
+                shouldUse.Visit(expression);
+            }
+
+            if (shouldUse.Properties.Any(p => p == GridPropertyInfo.PropertyPath))
+            {
+                return true;
+            }
+
+            return shouldUse.Properties.Any() == false;
+        }
+
         protected FilterOperator EnforceEqualityOperator()
         {
             var filterOperator = InnerFilterDescriptor.Operator;
             return acceptNullValuesWhenFiltering;
         }
 
-        private object ConvertValue(object value)
+        private object ResolveValue(object value)
         {
-            var valueResolvers = GridModelMapper.ConfigurationObject.ValueResolvers;
+            var valueResolvers = _queryValueResolvers;
 
-            var hasResolver = valueResolvers.HasResolverFor<TEntity, TViewModel>(GridPropertyInfo, value != null ? value.GetType() : null);
+            var hasResolver = valueResolvers != null && valueResolvers.HasResolverFor<TEntity, TViewModel>(GridPropertyInfo, value != null ? value.GetType() : null, true);
+
+            if (hasResolver)
+            {
+                return valueResolvers.Resolve<TEntity, TViewModel>(GridPropertyInfo, value, true);
+            }
+
+            valueResolvers = GridModelMapper.ConfigurationObject.ValueResolvers;
+
+            hasResolver = valueResolvers != null && valueResolvers.HasResolverFor<TEntity, TViewModel>(GridPropertyInfo, value != null ? value.GetType() : null);
 
             if (hasResolver)
             {
 
             var hasSubstituteFor = GridModelMapper.ConfigurationObject.BooleanSubstitutes.HasSubstituteFor<TEntity, TViewModel>(GridPropertyInfo);
 
-            if (hasSubstituteFor)
+            if (hasSubstituteFor || (value != null && value.GetType() == GridPropertyInfo.PropertyType))
             {
                 return value;
             }

TelerikMvcGridCustomBindingHelper/DynamicQuery/DynamicWhereClause.cs

 using System;
 using System.Collections.Generic;
-using System.Globalization;
 using System.Linq;
 using System.Linq.Expressions;
 using Telerik.Web.Mvc;
 
         public DynamicWhereClause() { }
 
-        public DynamicWhereClause(FilterDescriptor filterDescriptor, bool queryUseCaseInsensitiveSearch, bool queryAcceptNullValuesWhenFiltering)
-            : base(filterDescriptor, queryUseCaseInsensitiveSearch, queryAcceptNullValuesWhenFiltering)
+        public DynamicWhereClause(FilterDescriptor filterDescriptor, CaseInsensitive<TEntity> caseInsensitive, bool queryAcceptNullValuesWhenFiltering, ValueResolvers queryValueResolvers)
+            : base(filterDescriptor, caseInsensitive, queryAcceptNullValuesWhenFiltering, queryValueResolvers)
         {
             if (Predicate.IsNotNullOrWhiteSpace())
             {
                         var changeType = Reflector.ChangeType(nullValue, GridPropertyInfo.PropertyType);
                         if (GridPropertyInfo.PropertyType == typeof(string) && changeType != null && nullSubstitutes.IsCaseInsensitive)
                         {
-                            changeType = ((string)changeType).ToLowerInvariant();
+                            changeType = ((string)changeType).ToLower(GridModelMapper.ConfigurationObject.DefaultCulture);
                             caseInsensitive = true;
                         }
                         nullValues.Add(changeType);
 
         protected override string BuildPredicateCaseInsensitive(string value)
         {
-            _values.Add(value.ToLowerInvariant());
+            _values.Add(value.ToLower(GridModelMapper.ConfigurationObject.DefaultCulture));
             var property = string.Format("{0}.ToLowerInvariant()", TargetProperty);
 
             switch (InnerFilterDescriptor.Operator)

TelerikMvcGridCustomBindingHelper/DynamicQuery/ExpressionWhereClause.cs

             return Expression.Lambda<Func<TEntity, bool>>(expression, predicate.Parameters[0]);
         }
 
-        public ExpressionWhereClause(FilterDescriptor filterDescriptor, bool queryUseCaseInsensitiveSearch, bool queryAcceptNullValuesWhenFiltering)
-            : base(filterDescriptor, queryUseCaseInsensitiveSearch, queryAcceptNullValuesWhenFiltering) { }
+        public ExpressionWhereClause(FilterDescriptor filterDescriptor, CaseInsensitive<TEntity> caseInsensitive, bool queryAcceptNullValuesWhenFiltering, ValueResolvers queryValueResolvers)
+            : base(filterDescriptor, caseInsensitive, queryAcceptNullValuesWhenFiltering, queryValueResolvers) { }
 
         public ExpressionWhereClause() { }
 
                     var changeType = Reflector.TryChangeType(nullValue, GridPropertyInfo.PropertyType);
                     if (GridPropertyInfo.PropertyType == typeof(string) && changeType != null && nullSubstitutes.IsCaseInsensitive)
                     {
-                        changeType = ((string)changeType).ToLowerInvariant();
+                        changeType = ((string)changeType).ToLower(GridModelMapper.ConfigurationObject.DefaultCulture);
                         caseInsensitive = true;
                     }
                     if (nullValues.Any(o => Equals(o, changeType)) == false)
 
             if (caseInsensitive && value is string)
             {
-                value = ((string)value).ToLowerInvariant();
+                value = ((string)value).ToLower(GridModelMapper.ConfigurationObject.DefaultCulture);
 
                 exp = Expression.Lambda(Expression.Call(exp.Body, "ToLowerInvariant", null));
             }

TelerikMvcGridCustomBindingHelper/GridCustomBindingHelper.cs

 
         #region Fluent API
 
+        public new GridCustomBindingHelper<TEntity, TViewModel> AddValueResolver<TQueryValueResolver>(Expression<Func<TViewModel, object>> viewModelProperty) where TQueryValueResolver : class, IQueryValueResolver
+        {
+            return (GridCustomBindingHelper<TEntity, TViewModel>)base.AddValueResolver<TQueryValueResolver>(viewModelProperty);
+        }
+
+        public new GridCustomBindingHelper<TEntity, TViewModel> AddValueResolver<TQueryValueResolver>() where TQueryValueResolver : class, IQueryValueResolver
+        {
+            return (GridCustomBindingHelper<TEntity, TViewModel>)base.AddValueResolver<TQueryValueResolver>();
+        }
+
+        public new GridCustomBindingHelper<TEntity, TViewModel> AddValueResolver(IQueryValueResolver queryValueResolver)
+        {
+            return (GridCustomBindingHelper<TEntity, TViewModel>)base.AddValueResolver(queryValueResolver);
+        }
+
+        public new GridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(bool useCaseInsensitiveSearchOnBothClientAndServerSide = true)
+        {
+            return (GridCustomBindingHelper<TEntity, TViewModel>)base.UseCaseInsensitiveSearch(useCaseInsensitiveSearchOnBothClientAndServerSide);
+        }
+
+        public new GridCustomBindingHelper<TEntity, TViewModel> UseCaseInsensitiveSearch(Action<ICaseOptions<TEntity>> caseOptions)
+        {
+            return (GridCustomBindingHelper<TEntity, TViewModel>)base.UseCaseInsensitiveSearch(caseOptions);
+        }
+
         /// <summary>
         /// Adds a custom aggregate function.
         /// </summary>
         /// <returns>This same <see cref="GridCustomBindingHelper{TEntity,TViewModel}"/>.</returns>
         public GridCustomBindingHelper<TEntity, TViewModel> AddAggregateFunction<TAggregateFunction>(Expression<Func<TViewModel, object>> targetProperty) where TAggregateFunction : CustomAggregateFunction, new()
         {
-            return AddAggregateFunctionBase<TAggregateFunction>(targetProperty) as GridCustomBindingHelper<TEntity, TViewModel>;
+            return (GridCustomBindingHelper<TEntity, TViewModel>)AddAggregateFunctionBase<TAggregateFunction>(targetProperty);
         }
 
         /// <summary>
         /// <returns>This same <see cref="GridCustomBindingHelper{TEntity,TViewModel}"/>.</returns>
         public GridCustomBindingHelper<TEntity, TViewModel> AddAggregateFunction(Expression<Func<TViewModel, object>> targetProperty, Func<IQueryable<TEntity>, object> entitiesFunction, Func<IQueryable<TViewModel>, object> viewModelFunction = null)
         {
-            return AddAggregateFunctionBase(targetProperty, entitiesFunction, viewModelFunction) as GridCustomBindingHelper<TEntity, TViewModel>;
+            return (GridCustomBindingHelper<TEntity, TViewModel>)AddAggregateFunctionBase(targetProperty, entitiesFunction, viewModelFunction);
         }
 
         #endregion
                     else
                     {
                         var customExpression = gridPropertyInfo.CustomExpression;
-                        
+
                         var exp = Expression.Lambda<Func<TEntity, object>>(customExpression.Body, customExpression.Parameters);
                         data = AddSortExpression(data, exp, sortDescriptor.SortDirection, isFirst);
                     }
                     else
                     {
                         var filter = (FilterDescriptor)filterDescriptor;
-                        var whereClause = new ExpressionWhereClause<TEntity, TViewModel>(filter, UseCaseInsensitiveSearchField, AcceptNullValuesWhenFilteringField);
+                        var whereClause = new ExpressionWhereClause<TEntity, TViewModel>(filter, CaseInsensitiveField, AcceptNullValuesWhenFilteringField, QueryValueResolvers);
 
                         if (logicalOperator == FilterCompositionLogicalOperator.And)
                         {
                     else
                     {
                         var filter = (FilterDescriptor)filterDescriptor;
-                        var whereClause = new DynamicWhereClause<TEntity, TViewModel>(filter, UseCaseInsensitiveSearchField, AcceptNullValuesWhenFilteringField);
+                        var whereClause = new DynamicWhereClause<TEntity, TViewModel>(filter, CaseInsensitiveField, AcceptNullValuesWhenFilteringField, QueryValueResolvers);
 
                         if (logicalOperator == FilterCompositionLogicalOperator.And)
                         {

TelerikMvcGridCustomBindingHelper/Mapper/FluentMapperConfiguration.cs

 
         IFluentMapperConfiguration AcceptNullValuesWhenFiltering(bool acceptNullValuesWhenFiltering = true);
         IFluentMapperConfiguration AcceptNullValuesWhenFiltering<TEntity>(bool acceptNullValuesWhenFiltering = true);
-        IFluentMapperConfiguration UseCaseInsensitiveSearch(bool useCaseInsensitiveSearch = true);
+        IFluentMapperConfiguration UseCaseInsensitiveSearch(Action<IBaseCaseOptions> caseOptions);
+        IFluentMapperConfiguration UseCaseInsensitiveSearch(bool useCaseInsensitiveSearchOnBothClientAndServerSide = true);
         IFluentMapperConfiguration DefaultSortMemberName(IDMemberName idMemberName, string memberNameOrPrefixOrSuffix, ListSortDirection sortDirection = ListSortDirection.Ascending);
         IFluentMapperConfiguration DefaultSortMemberName(IDMemberName idMemberName, ListSortDirection sortDirection);
         IFluentMapperConfiguration DefaultSortMemberName(IDMemberName idMemberName);
         internal Func<IORMIntegration> ORMIntegrationFactory { get; private set; }
         internal ITinyCache<string> TinyCache { get; private set; }
         internal bool ShouldCreateSimpleMappingsAsNeeded { get; private set; }
-        internal bool GlobalUseCaseInsensitiveSearch { get; private set; }
+        internal IBaseCaseOptions GlobalCaseInsensitiveSearchOptions { get; private set; }
         internal bool ShouldAcceptNullValuesWhenFiltering { get; private set; }
         internal AcceptNullValuesWhenFilteringType AcceptNullValuesWhenFilteringType { get; private set; }
         internal bool ShouldFallBackToLinqExpressionBuilder { get; private set; }
             return this;
         }
 
-        IFluentMapperConfiguration IFluentMapperConfiguration.UseCaseInsensitiveSearch(bool useCaseInsensitiveSearch)
+        IFluentMapperConfiguration IFluentMapperConfiguration.UseCaseInsensitiveSearch(Action<IBaseCaseOptions> caseOptions)
         {
-            GlobalUseCaseInsensitiveSearch = useCaseInsensitiveSearch;
+            GlobalCaseInsensitiveSearchOptions = new CaseInsensitive<object>();
+            caseOptions(GlobalCaseInsensitiveSearchOptions);
+            return this;
+        }
+
+        IFluentMapperConfiguration IFluentMapperConfiguration.UseCaseInsensitiveSearch(bool useCaseInsensitiveSearchOnBothClientAndServerSide)
+        {
+            GlobalCaseInsensitiveSearchOptions = new CaseInsensitive<object>();
+            GlobalCaseInsensitiveSearchOptions.BothClientAndServerSide(useCaseInsensitiveSearchOnBothClientAndServerSide);
             return this;
         }
 

TelerikMvcGridCustomBindingHelper/Mapper/IValueResolver.cs

         object Resolve(ResultContext source);
     }
 
+    public interface IQueryValueResolver : IGlobalValueResolver
+    {
+        void SetTargetProperty(string targetProperty);
+        string GetTargetProperty();
+    }
+
+    public abstract class QueryValueResolver<TSource, TDestination> : GlobalValueResolver<TSource, TDestination>, IQueryValueResolver
+    {
+        private string _targetProperty;
+
+        public void SetTargetProperty(string targetProperty)
+        {
+            _targetProperty = targetProperty;
+        }
+
+        public string GetTargetProperty()
+        {
+            return _targetProperty;
+        }
+    }
+
     public interface IGlobalValueResolver : IValueResolver
     {
         Type GetSourceType();
     {
         public object Resolve(ResultContext source)
         {
-            object value = null;
+            var value = source.Value;
 
             if (!(source.Value is TSource))
             {
-                value = Reflector.TryChangeType(source.Value, typeof (TSource), GridModelMapper.ConfigurationObject.DefaultCulture);
+                value = Reflector.TryChangeType(source.Value, typeof(TSource), GridModelMapper.ConfigurationObject.DefaultCulture);
                 if (value == null && source.Value != null)
                 {
                     throw new AutoMapperMappingException(string.Format("Value supplied is of type {0} but expected {1}.\nChange the value resolver source type, or redirect the source value supplied to the value resolver using FromMember.", typeof(TSource), source.Value.GetType()));

TelerikMvcGridCustomBindingHelper/Mapper/NullAliases.cs

                 {
                     if (nullAlias.Aliases()
                         .Where(nullValue => nullValue != null)
-                        .Any(nullValue => nullValue.ToString().ToLowerInvariant()
-                            .Equals(convertedValue.ToString().ToLowerInvariant())))
+                        .Any(nullValue => nullValue.ToString().ToLower(GridModelMapper.ConfigurationObject.DefaultCulture)
+                            .Equals(convertedValue.ToString().ToLower(GridModelMapper.ConfigurationObject.DefaultCulture))))
                     {
                         return true;
                     }

TelerikMvcGridCustomBindingHelper/Mapper/ValueResolvers.cs

 using System;
 using System.Collections.Concurrent;
+using System.Linq;
 using TelerikMvcGridCustomBindingHelper.Util;
 
 namespace TelerikMvcGridCustomBindingHelper.Mapper
 {
-    internal class ValueResolvers : ConcurrentDictionary<ValueResolverKey, IValueResolver>
+    public class ValueResolvers : ConcurrentDictionary<ValueResolverKey, IValueResolver>
     {
-        public bool HasResolverFor<TEntity, TViewModel>(GridPropertyInfo gridPropertyInfo, Type valueType)
+        public bool HasResolverFor<TEntity, TViewModel>(GridPropertyInfo gridPropertyInfo, Type valueType, bool searshForQueryValueResolvers = false)
         {
             Contract.Expect(() => gridPropertyInfo).IsNotNull();
 
+            if (searshForQueryValueResolvers)
+            {
+                return Values.Where(resolver => resolver is IQueryValueResolver).Any(resolver => _targetPropertyMatch((IQueryValueResolver)resolver, gridPropertyInfo));
+            }
+
             var result = ContainsKey(ValueResolverKey.New(typeof(TEntity), typeof(TViewModel), gridPropertyInfo));
 
-            if (valueType != null)
+            if (result == false && valueType != null)
             {
-                result = result || ContainsKey(ValueResolverKey.GlobalKey(valueType, gridPropertyInfo.PropertyType));
+                result = ContainsKey(ValueResolverKey.GlobalKey(valueType, gridPropertyInfo.PropertyType));
             }
 
             if (result == false && (gridPropertyInfo.PropertyType != null && gridPropertyInfo.ViewModelPropertyType != null))
             return result;
         }
 
-        public object Resolve<TEntity, TViewModel>(GridPropertyInfo gridPropertyInfo, object value)
+        public object Resolve<TEntity, TViewModel>(GridPropertyInfo gridPropertyInfo, object value, bool searshForQueryValueResolvers = false)
         {
             IValueResolver valueResolver;
 
                 tryGetValue = TryGetValue(ValueResolverKey.GlobalKey(gridPropertyInfo.ViewModelPropertyType, gridPropertyInfo.PropertyType), out valueResolver);
             }
 
+            if (searshForQueryValueResolvers)
+            {
+                valueResolver = Values.Where(resolver => resolver is IQueryValueResolver).FirstOrDefault(resolver => _targetPropertyMatch((IQueryValueResolver)resolver, gridPropertyInfo));
+                tryGetValue = valueResolver != null;
+            }
+
             return tryGetValue == false ? value : valueResolver.Resolve(rc);
         }
+
+        readonly Func<IQueryValueResolver, GridPropertyInfo, bool> _targetPropertyMatch = (resolver, gpi) =>
+        {
+            if (resolver.GetTargetProperty().IsNullOrWhiteSpace())
+                return true;
+
+            var match = resolver.GetTargetProperty().Equals(gpi.ViewModelProperty.GetPropertyPath() ?? gpi.PropertyPath);
+
+            if (match)
+                return resolver.GetDestinationType() == gpi.PropertyType;
+
+            return false;
+        };
     }
 
-    internal struct ValueResolverKey : IEquatable<ValueResolverKey>
+    public struct ValueResolverKey : IEquatable<ValueResolverKey>
     {
         public readonly Type EntityType;
         public readonly Type ViewModelType;
             return new ValueResolverKey(sourceType, destinationType, gpi);
         }
 
+        public static ValueResolverKey QueryKey(IQueryValueResolver queryValueResolver)
+        {
+            if (queryValueResolver.GetTargetProperty().IsNullOrWhiteSpace())
+                return GlobalKey(queryValueResolver.GetSourceType(), queryValueResolver.GetDestinationType());
+
+            var sourceType = queryValueResolver.GetSourceType();
+            var destinationType = queryValueResolver.GetDestinationType();
+
+            var gpi = new GridPropertyInfo(sourceType, queryValueResolver.GetTargetProperty());
+            return new ValueResolverKey(sourceType, destinationType, gpi);
+        }
+
         #region IEquatable<ValueResolverKey>
 
         public bool Equals(ValueResolverKey other)

TelerikMvcGridCustomBindingHelper/Projections/ProjectionsEngine.cs

 
             if (options != null)
             {
-                if (options.PropertiesToUseOnly.Any())
+                if (options.PropertiesToUse.Any())
                 {
-                    foreach (var expression in options.PropertiesToUseOnly)
+                    foreach (var expression in options.PropertiesToUse)
                     {
                         visitor.Visit(expression);
                     }

TelerikMvcGridCustomBindingHelper/Projections/ProjectionsOptions.cs

     {
         internal readonly List<Expression> PropertiesToIgnore = new List<Expression>();
         internal readonly List<Expression> PropertiesToInclude = new List<Expression>();
-        internal readonly List<Expression> PropertiesToUseOnly = new List<Expression>();
+        internal readonly List<Expression> PropertiesToUse = new List<Expression>();
 
         public IProjectionsOptions<TEntity> Ignore(Expression<Func<TEntity, object>> selector)
         {
-            PropertiesToIgnore.AddRange(new[] { selector });
+            PropertiesToIgnore.Add(selector);
             return this;
         }
 
         public IProjectionsOptions<TEntity> Include(Expression<Func<TEntity, object>> selector)
         {
-            PropertiesToInclude.AddRange(new[] { selector });
+            PropertiesToInclude.Add(selector);
             return this;
         }
 
         public IProjectionsOptions<TEntity> Use(Expression<Func<TEntity, object>> selector)
         {
-            PropertiesToUseOnly.AddRange(new[] { selector });
+            PropertiesToUse.Add(selector);
             return this;
         }
     }
         {
             var str = GetType().ToString();
 
-            str += PropertiesToUseOnly.Aggregate("\n\tPropertiesToUseOnly: ", (current, expression) => current + string.Join(";", expression.ToString()));
+            str += PropertiesToUse.Aggregate("\n\tPropertiesToUseOnly: ", (current, expression) => current + string.Join(";", expression.ToString()));
 
-            str += PropertiesToIgnore.Aggregate("\n\tPropertiesToIgnore : ", (current, expression) => current + string.Join(";", expression.ToString()));
+            str += PropertiesToIgnore.Aggregate("\n\tPropertiesToIgnore: ", (current, expression) => current + string.Join(";", expression.ToString()));
 
             str += PropertiesToInclude.Aggregate("\n\tPropertiesToInclude: ", (current, expression) => current + string.Join(";", expression.ToString()));
 

TelerikMvcGridCustomBindingHelper/Properties/SystemInfo.cs

         /// by using the '*' as shown below:
         /// [assembly: AssemblyVersion("1.0.*")]
         /// </summary>
-        public const string Version = "1.0.15.279";
+        public const string Version = "1.0.15.312";
         public const string FileVersion = Version;
         public const string Trademark = "@ Luis Fernando de Souza Santos - Lukian";
         public const string Copyright = "Copyright © Luis Fernando de Souza Santos - Lukian - 2012";

TelerikMvcGridCustomBindingHelper/TelerikMvcGridCustomBindingHelper.csproj

     <Compile Include="Aggregates\AggregatesBuilder.cs" />
     <Compile Include="Aggregates\AggregatesContainer.cs" />
     <Compile Include="Aggregates\CustomAggregateFunctionsGroup.cs" />
+    <Compile Include="CaseInsensitive.cs" />
     <Compile Include="DynamicQuery\BaseDynamicWhereClause.cs" />
     <Compile Include="DynamicQuery\DynamicWhereClause.cs" />
     <Compile Include="DynamicQuery\ExpressionWhereClause.cs" />

TelerikMvcGridCustomBindingHelper/Util/Extencions.cs

 
         public static string GetPropertyPath(this Expression expression)
         {
-            var hashSet = GetAllPropertiesPaths(expression);
+            var hashSet = GetAllPropertiesPaths(expression) ?? new HashSet<string>();
             return hashSet.Any() ? hashSet.ElementAt(0) : null;
         }
 
         public static HashSet<string> GetAllPropertiesPaths(this Expression expression)
         {
-            Guard.IsNotNull(() => expression);
+            if (expression == null)
+                return null;
 
             var visitor = new PropertyPathVisitor();
             visitor.Visit(expression);

TelerikMvcGridCustomBindingHelper/_ReadMe/Features.txt

 * Integration with ORMs  through the interface IORMIntegration or INHibernateIntegration;
 * BooleanSubstitutes and GlobalBooleanSubstitutes;
 * CustomValueResolvers and GlobalValueResolvers;
-* Configurable null behavior when filtering (AcceptNullValuesWhenFiltering, NullSubstitutes and NullAliases).
+* Configurable null behavior when filtering (AcceptNullValuesWhenFiltering, NullSubstitutes and NullAliases);
+* Case-insensitive search globally, by query, property (or set of properties), client and server side (or both).
 
 **Please provide feedback/input on this release (http://tgh.codeplex.com/discussions).

TelerikMvcGridCustomBindingHelper/_ReadMe/ReleaseNotes.txt

-# TelerikMvcGridCustomBindingHelper 1.0.15.??? RC4 (Released on ??/10/2012)
+# TelerikMvcGridCustomBindingHelper 1.0.15.312 RC4 (Released on 08/11/2012)
 
 Release notes:
 
 * Support for CustomExpressions on property maps: GMMapper.CreateMap(...).MapProperty(Entity.FirstName + " " + Entity.LastName, VModel.FullName)
 * Updates NHibernate from v.3.3.1 to v.3.3.2
 * Merge inner properties to prevent duplicate mappings
-* BetterSqlProjection mow ignore cast when sorting
+* BetterSqlProjection now ignore cast when sorting
 * bugfix on creation of subcriterias for NHibernate
-* Reached 1.475 unit tests!
-* Large numbers filter support
+* Large-numbers filter support
+* More granular control over case-insensitive search
+* ValueResolvers can now be added to a single query
+* Reached 1.722 unit tests!
 
 # TelerikMvcGridCustomBindingHelper 1.0.15.247 RC3 (Released on 06/10/2012)
 

Tests/DatabaseTests/DBCaseInsensitiveSearchTests.cs

             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Name);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "nAmE5"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "nAmE5" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "Alternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "Alternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.IsNotEqualTo, Value = "Not Alternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.IsNotEqualTo, Value = "Not Alternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.StartsWith, Value = "Alternate Cas"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.StartsWith, Value = "Alternate Cas" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.EndsWith, Value = "lternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.EndsWith, Value = "lternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.DoesNotContain, Value = "5Alternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.DoesNotContain, Value = "5Alternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.Contains, Value = "lternate Cas"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.Contains, Value = "lternate Cas" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.Query<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Name);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "nAmE5"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "nAmE5" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "Alternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.IsEqualTo, Value = "Alternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.IsNotEqualTo, Value = "Not Alternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.IsNotEqualTo, Value = "Not Alternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.StartsWith, Value = "Alternate Cas"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.StartsWith, Value = "Alternate Cas" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.EndsWith, Value = "lternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.EndsWith, Value = "lternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.DoesNotContain, Value = "5Alternate Case"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.DoesNotContain, Value = "5Alternate Case" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();
             var command = new GridCommand();
             var propertyPath = Reflector.GetPropertyPath<FooModel>(fooModel => fooModel.Description);
 
-            var filterDescriptor = new FilterDescriptor
-                {Member = propertyPath, Operator = FilterOperator.Contains, Value = "lternate Cas"};
+            var filterDescriptor = new FilterDescriptor { Member = propertyPath, Operator = FilterOperator.Contains, Value = "lternate Cas" };
             command.FilterDescriptors.Add(filterDescriptor);
 
             var data = Session.QueryOver<Foo>();

Tests/DynamicWhereClause/DynamicWhereClauseTests.cs

 using FluentAssertions;
 using NUnit.Framework;
 using Telerik.Web.Mvc;
+using TelerikMvcGridCustomBindingHelper;
 using TelerikMvcGridCustomBindingHelper.DynamicQuery;
 using TelerikMvcGridCustomBindingHelper.Mapper;
 using TelerikMvcGridCustomBindingHelper.Util;
         public void expressionWhereClause_single_expressions_with_booleanSubstitute(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithBooleanSubstituteTests+Foo", "foo").Should().Be(exp.ToString());
         }
         public void expressionWhereClause_double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithBooleanSubstituteTests+Foo", "foo").Should().Be(exp.ToString());
 
         public void expressionWhereClause_double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithBooleanSubstituteTests+Foo", "foo").Should().Be(exp.ToString());
 
         public void expressionWhereClause_single_expressions_with_booleanSubstitute(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullSubstituteTests+Foo", "foo")
         public void expressionWhereClause_double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullSubstituteTests+Foo", "foo")
         public void expressionWhereClause_double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullSubstituteTests+Foo", "foo")
         public void expressionWhereClause_single_expressions_with_booleanSubstitute(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullSubstituteWithCaseInsensitiveTests+Foo", "foo")
         public void expressionWhereClause_double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullSubstituteWithCaseInsensitiveTests+Foo", "foo")
         public void expressionWhereClause_double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullSubstituteWithCaseInsensitiveTests+Foo", "foo")
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasTests+Foo", "foo")
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasTests+Foo", "foo")
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasTests+Foo", "foo")
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndSearchExplicitTests+Foo", "foo")
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndSearchExplicitTests+Foo", "foo")
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndSearchExplicitTests+Foo", "foo")
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndCaseInsensitiveTests+Foo", "foo")
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndCaseInsensitiveTests+Foo", "foo")
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndCaseInsensitiveTests+Foo", "foo")
         {
             var filter = new FilterDescriptor(member, @operator, value);
 
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndCaseInsensitiveTests+Foo", "foo")
         public void double_expressions_with_gridModelMapper_customExpression_and_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndCaseInsensitiveTests+Foo", "foo")
         public void double_expressions_with_gridModelMapper_customExpression_and_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString()
                 .Replace("Tests.DynamicWhereClause.ExpressionWhereClauseWithNullAliasAndCaseInsensitiveTests+Foo", "foo")
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), true, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString().Replace(".Value", ""));
         }
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), true, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString().Replace(".Value", ""));
 
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), true, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString().Replace(".Value", ""));
 
         {
             var filter = new FilterDescriptor(member, @operator, value);
 
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), true, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
         }
         public void double_expressions_with_gridModelMapper_customExpression_and_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), true, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
 
         public void double_expressions_with_gridModelMapper_customExpression_and_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), true, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
 
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, true, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString().Replace(".Value", ""));
         }
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, true, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString().Replace(".Value", ""));
 
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, true, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString().Replace(".Value", ""));
 
         {
             var filter = new FilterDescriptor(member, @operator, value);
 
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, true, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
         }
         public void double_expressions_with_gridModelMapper_customExpression_and_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, true, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
 
         public void double_expressions_with_gridModelMapper_customExpression_and_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, true);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, true, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
 
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
         }
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
 
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
 
         {
             var filter = new FilterDescriptor(member, @operator, value);
 
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), false, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
         }
         public void double_expressions_with_gridModelMapper_customExpression_and_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), false, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
 
         public void double_expressions_with_gridModelMapper_customExpression_and_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, true, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
+
+            expressionWhereClause.AndAlso(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.AndAlso(exp).ToString().Replace("Convert(5)", "5"));
+        }
+    }
+
+    public class ExpressionWhereClauseWithClientSideCaseInsensitiveTests
+    {
+        [SetUp]
+        public void SetUp()
+        {
+            Mapper.Reset();
+            GridModelMapper.Reset();
+            GridModelMapper.CreateMap<Foo, FooModel>()
+                .MapProperty(foo => foo.FirstName + " " + foo.LastName, model => model.FullName)
+                .MapProperty(foo => foo.UnitPrice + foo.UnitsInStock, model => model.TotalPrice);
+        }
+
+        #region ExpressionCases
+
+        // ReSharper disable InconsistentNaming
+        static readonly Expression<Func<Foo, bool>> Exp_IsLessThan = foo => foo.UnitPrice < 5;
+        static readonly Expression<Func<Foo, bool>> Exp_IsLessThanOrEqualTo = foo => foo.UnitPrice <= 5;
+        static readonly Expression<Func<Foo, bool>> Exp_IsGreaterThanOrEqualTo = foo => foo.UnitPrice >= 5;
+        static readonly Expression<Func<Foo, bool>> Exp_IsGreaterThan = foo => foo.UnitPrice > 5;
+        static readonly Expression<Func<Foo, bool>> Exp_StartsWith = foo => foo.Name.StartsWith("luis");
+        static readonly Expression<Func<Foo, bool>> Exp_EndsWith = foo => foo.Name.EndsWith("luis");
+        static readonly Expression<Func<Foo, bool>> Exp_Contains = foo => foo.Name.Contains("luis");
+        static readonly Expression<Func<Foo, bool>> Exp_DoesNotContains = foo => !foo.Name.Contains("luis");
+        static readonly Expression<Func<Foo, bool>> Exp_IsEqualTo = foo => foo.Name == "luis";
+        static readonly Expression<Func<Foo, bool>> Exp_IsNotEqualTo = foo => foo.Name != "luis";
+        static readonly Expression<Func<Foo, bool>> Exp_NullLiteralIsEqualTo = foo => foo.Name == null;
+        static readonly Expression<Func<Foo, bool>> Exp_NullLiteralIsNotEqualTo = foo => foo.Name != null;
+
+        static readonly object[] ExpressionCases =
+        {
+            new object[] { "UnitPrice", FilterOperator.IsLessThan, Exp_IsLessThan, 5 },
+            new object[] { "UnitPrice", FilterOperator.IsLessThanOrEqualTo, Exp_IsLessThanOrEqualTo, "5" },
+            new object[] { "UnitPrice", FilterOperator.IsGreaterThanOrEqualTo, Exp_IsGreaterThanOrEqualTo, "5" },
+            new object[] { "UnitPrice", FilterOperator.IsGreaterThan, Exp_IsGreaterThan, "5" },
+            new object[] { "Name", FilterOperator.StartsWith, Exp_StartsWith, "Luis" },
+            new object[] { "Name", FilterOperator.EndsWith, Exp_EndsWith, "Luis" },
+            new object[] { "Name", FilterOperator.Contains, Exp_Contains, "Luis" },
+            new object[] { "Name", FilterOperator.DoesNotContain, Exp_DoesNotContains, "Luis" },
+            new object[] { "Name", FilterOperator.IsEqualTo, Exp_IsEqualTo, "Luis" },
+            new object[] { "Name", FilterOperator.IsNotEqualTo, Exp_IsNotEqualTo, "Luis" },
+            new object[] { "Name", FilterOperator.IsNotEqualTo, Exp_NullLiteralIsNotEqualTo, null },
+            new object[] { "Name", FilterOperator.IsEqualTo, Exp_NullLiteralIsEqualTo, null }
+        };
+        // ReSharper restore InconsistentNaming
+
+        #endregion
+
+        [TestCaseSource("ExpressionCases")]
+        public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(false, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
+        }
+
+        [TestCaseSource("ExpressionCases")]
+        public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(false, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
+
+            expressionWhereClause.OrElse(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.OrElse(exp).ToString());
+        }
+
+        [TestCaseSource("ExpressionCases")]
+        public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(false, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
+
+            expressionWhereClause.AndAlso(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.AndAlso(exp).ToString());
+        }
+
+        #region CustomExpression_Cases
+
+        // ReSharper disable InconsistentNaming
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsLessThan = foo => foo.UnitPrice + foo.UnitsInStock < 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsLessThanOrEqualTo = foo => foo.UnitPrice + foo.UnitsInStock <= 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsGreaterThanOrEqualTo = foo => foo.UnitPrice + foo.UnitsInStock >= 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsGreaterThan = foo => foo.UnitPrice + foo.UnitsInStock > 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_StartsWith = foo => (foo.FirstName + " " + foo.LastName).StartsWith("luis fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_EndsWith = foo => (foo.FirstName + " " + foo.LastName).EndsWith("luis fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_Contains = foo => (foo.FirstName + " " + foo.LastName).Contains("luis fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_DoesNotContains = foo => !(foo.FirstName + " " + foo.LastName).Contains("luis fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsEqualTo = foo => (foo.FirstName + " " + foo.LastName) == "luis fernando";
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsNotEqualTo = foo => (foo.FirstName + " " + foo.LastName) != "luis fernando";
+        static readonly Expression<Func<Foo, bool>> CustomExpression_NullLiteralIsEqualTo = foo => foo.FirstName + " " + foo.LastName == null;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_NullLiteralIsNotEqualTo = foo => foo.FirstName + " " + foo.LastName != null;
+
+        static readonly object[] CustomExpression_Cases =
+        {
+            new object[] { "TotalPrice", FilterOperator.IsLessThan, CustomExpression_IsLessThan, 5 },
+            new object[] { "TotalPrice", FilterOperator.IsLessThanOrEqualTo, CustomExpression_IsLessThanOrEqualTo, "5" },
+            new object[] { "TotalPrice", FilterOperator.IsGreaterThanOrEqualTo, CustomExpression_IsGreaterThanOrEqualTo, "5" },
+            new object[] { "TotalPrice", FilterOperator.IsGreaterThan, CustomExpression_IsGreaterThan, "5" },
+            new object[] { "FullName", FilterOperator.StartsWith, CustomExpression_StartsWith, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.EndsWith, CustomExpression_EndsWith, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.Contains, CustomExpression_Contains, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.DoesNotContain, CustomExpression_DoesNotContains, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.IsEqualTo, CustomExpression_IsEqualTo, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.IsNotEqualTo, CustomExpression_IsNotEqualTo, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.IsEqualTo, CustomExpression_NullLiteralIsEqualTo, null },
+            new object[] { "FullName", FilterOperator.IsNotEqualTo, CustomExpression_NullLiteralIsNotEqualTo, null }
+        };
+        // ReSharper restore InconsistentNaming
+
+        #endregion
+
+        [TestCaseSource("CustomExpression_Cases")]
+        public void single_expressions_with_gridModelMapper_customExpression(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(false, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
+        }
+
+        [TestCaseSource("CustomExpression_Cases")]
+        public void double_expressions_with_gridModelMapper_customExpression_and_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(false, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
+
+            expressionWhereClause.OrElse(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.OrElse(exp).ToString().Replace("Convert(5)", "5"));
+        }
+
+        [TestCaseSource("CustomExpression_Cases")]
+        public void double_expressions_with_gridModelMapper_customExpression_and_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(false, true), false, null);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
+
+            expressionWhereClause.AndAlso(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.AndAlso(exp).ToString().Replace("Convert(5)", "5"));
+        }
+    }
+
+    public class ExpressionWhereClauseWithServerSideCaseInsensitiveTests
+    {
+        [SetUp]
+        public void SetUp()
+        {
+            Mapper.Reset();
+            GridModelMapper.Reset();
+            GridModelMapper.CreateMap<Foo, FooModel>()
+                .MapProperty(foo => foo.FirstName + " " + foo.LastName, model => model.FullName)
+                .MapProperty(foo => foo.UnitPrice + foo.UnitsInStock, model => model.TotalPrice);
+        }
+
+        #region ExpressionCases
+
+        // ReSharper disable InconsistentNaming
+        static readonly Expression<Func<Foo, bool>> Exp_IsLessThan = foo => foo.UnitPrice < 5;
+        static readonly Expression<Func<Foo, bool>> Exp_IsLessThanOrEqualTo = foo => foo.UnitPrice <= 5;
+        static readonly Expression<Func<Foo, bool>> Exp_IsGreaterThanOrEqualTo = foo => foo.UnitPrice >= 5;
+        static readonly Expression<Func<Foo, bool>> Exp_IsGreaterThan = foo => foo.UnitPrice > 5;
+        static readonly Expression<Func<Foo, bool>> Exp_StartsWith = foo => foo.Name.ToLowerInvariant().StartsWith("Luis");
+        static readonly Expression<Func<Foo, bool>> Exp_EndsWith = foo => foo.Name.ToLowerInvariant().EndsWith("Luis");
+        static readonly Expression<Func<Foo, bool>> Exp_Contains = foo => foo.Name.ToLowerInvariant().Contains("Luis");
+        static readonly Expression<Func<Foo, bool>> Exp_DoesNotContains = foo => !foo.Name.ToLowerInvariant().Contains("Luis");
+        static readonly Expression<Func<Foo, bool>> Exp_IsEqualTo = foo => foo.Name.ToLowerInvariant() == "Luis";
+        static readonly Expression<Func<Foo, bool>> Exp_IsNotEqualTo = foo => foo.Name.ToLowerInvariant() != "Luis";
+        static readonly Expression<Func<Foo, bool>> Exp_NullLiteralIsEqualTo = foo => foo.Name == null;
+        static readonly Expression<Func<Foo, bool>> Exp_NullLiteralIsNotEqualTo = foo => foo.Name != null;
+
+        static readonly object[] ExpressionCases =
+        {
+            new object[] { "UnitPrice", FilterOperator.IsLessThan, Exp_IsLessThan, 5 },
+            new object[] { "UnitPrice", FilterOperator.IsLessThanOrEqualTo, Exp_IsLessThanOrEqualTo, "5" },
+            new object[] { "UnitPrice", FilterOperator.IsGreaterThanOrEqualTo, Exp_IsGreaterThanOrEqualTo, "5" },
+            new object[] { "UnitPrice", FilterOperator.IsGreaterThan, Exp_IsGreaterThan, "5" },
+            new object[] { "Name", FilterOperator.StartsWith, Exp_StartsWith, "Luis" },
+            new object[] { "Name", FilterOperator.EndsWith, Exp_EndsWith, "Luis" },
+            new object[] { "Name", FilterOperator.Contains, Exp_Contains, "Luis" },
+            new object[] { "Name", FilterOperator.DoesNotContain, Exp_DoesNotContains, "Luis" },
+            new object[] { "Name", FilterOperator.IsEqualTo, Exp_IsEqualTo, "Luis" },
+            new object[] { "Name", FilterOperator.IsNotEqualTo, Exp_IsNotEqualTo, "Luis" },
+            new object[] { "Name", FilterOperator.IsNotEqualTo, Exp_NullLiteralIsNotEqualTo, null },
+            new object[] { "Name", FilterOperator.IsEqualTo, Exp_NullLiteralIsEqualTo, null }
+        };
+        // ReSharper restore InconsistentNaming
+
+        #endregion
+
+        [TestCaseSource("ExpressionCases")]
+        public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, false), false, null);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
+        }
+
+        [TestCaseSource("ExpressionCases")]
+        public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, false), false, null);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
+
+            expressionWhereClause.OrElse(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.OrElse(exp).ToString());
+        }
+
+        [TestCaseSource("ExpressionCases")]
+        public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, false), false, null);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
+
+            expressionWhereClause.AndAlso(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.AndAlso(exp).ToString());
+        }
+
+        #region CustomExpression_Cases
+
+        // ReSharper disable InconsistentNaming
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsLessThan = foo => foo.UnitPrice + foo.UnitsInStock < 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsLessThanOrEqualTo = foo => foo.UnitPrice + foo.UnitsInStock <= 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsGreaterThanOrEqualTo = foo => foo.UnitPrice + foo.UnitsInStock >= 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsGreaterThan = foo => foo.UnitPrice + foo.UnitsInStock > 5;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_StartsWith = foo => (foo.FirstName + " " + foo.LastName).ToLowerInvariant().StartsWith("Luis Fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_EndsWith = foo => (foo.FirstName + " " + foo.LastName).ToLowerInvariant().EndsWith("Luis Fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_Contains = foo => (foo.FirstName + " " + foo.LastName).ToLowerInvariant().Contains("Luis Fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_DoesNotContains = foo => !(foo.FirstName + " " + foo.LastName).ToLowerInvariant().Contains("Luis Fernando");
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsEqualTo = foo => (foo.FirstName + " " + foo.LastName).ToLowerInvariant() == "Luis Fernando";
+        static readonly Expression<Func<Foo, bool>> CustomExpression_IsNotEqualTo = foo => (foo.FirstName + " " + foo.LastName).ToLowerInvariant() != "Luis Fernando";
+        static readonly Expression<Func<Foo, bool>> CustomExpression_NullLiteralIsEqualTo = foo => foo.FirstName + " " + foo.LastName == null;
+        static readonly Expression<Func<Foo, bool>> CustomExpression_NullLiteralIsNotEqualTo = foo => foo.FirstName + " " + foo.LastName != null;
+
+        static readonly object[] CustomExpression_Cases =
+        {
+            new object[] { "TotalPrice", FilterOperator.IsLessThan, CustomExpression_IsLessThan, 5 },
+            new object[] { "TotalPrice", FilterOperator.IsLessThanOrEqualTo, CustomExpression_IsLessThanOrEqualTo, "5" },
+            new object[] { "TotalPrice", FilterOperator.IsGreaterThanOrEqualTo, CustomExpression_IsGreaterThanOrEqualTo, "5" },
+            new object[] { "TotalPrice", FilterOperator.IsGreaterThan, CustomExpression_IsGreaterThan, "5" },
+            new object[] { "FullName", FilterOperator.StartsWith, CustomExpression_StartsWith, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.EndsWith, CustomExpression_EndsWith, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.Contains, CustomExpression_Contains, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.DoesNotContain, CustomExpression_DoesNotContains, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.IsEqualTo, CustomExpression_IsEqualTo, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.IsNotEqualTo, CustomExpression_IsNotEqualTo, "Luis Fernando" },
+            new object[] { "FullName", FilterOperator.IsEqualTo, CustomExpression_NullLiteralIsEqualTo, null },
+            new object[] { "FullName", FilterOperator.IsNotEqualTo, CustomExpression_NullLiteralIsNotEqualTo, null }
+        };
+        // ReSharper restore InconsistentNaming
+
+        #endregion
+
+        [TestCaseSource("CustomExpression_Cases")]
+        public void single_expressions_with_gridModelMapper_customExpression(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, false), false, null);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
+        }
+
+        [TestCaseSource("CustomExpression_Cases")]
+        public void double_expressions_with_gridModelMapper_customExpression_and_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, false), false, null);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
+
+            expressionWhereClause.OrElse(expressionWhereClause);
+
+            expressionWhereClause.Predicate.ToString().Should().Be(exp.OrElse(exp).ToString().Replace("Convert(5)", "5"));
+        }
+
+        [TestCaseSource("CustomExpression_Cases")]
+        public void double_expressions_with_gridModelMapper_customExpression_and_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
+        {
+            var filter = new FilterDescriptor(member, @operator, value);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, new CaseInsensitive<Foo>(true, false), false, null);
 
             expressionWhereClause.Predicate.ToString().Should().Be(exp.ToString().Replace("Convert(5)", "5"));
 
         public void single_expressions(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
         }
         public void double_expressions_with_orElse_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
 
         public void double_expressions_with_andAlso_operator(string member, FilterOperator @operator, Expression<Func<Foo, bool>> exp, object value)
         {
             var filter = new FilterDescriptor(member, @operator, value);
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);
+            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, null, false, null);
 
             expressionWhereClause.Predicate.ToString().Replace("Tests.Entity.Foo", "foo").Should().Be(exp.ToString());
 
         {
             var filter = new FilterDescriptor(member, @operator, value);
 
-            var expressionWhereClause = new ExpressionWhereClause<Foo, FooModel>(filter, false, false);