@@ -44,7 +44,7 @@ public static IOrderedQueryable<TSource> CustomOrderBy<TSource>(
4444 . Where ( m =>
4545 {
4646 var parameters = m . GetParameters ( ) . ToList ( ) ;
47- //Put more restriction here to ensure selecting the right overload
47+ //Put more restriction here to ensure selecting the right overload
4848 return parameters . Count == 2 ; //overload that has 2 parameters
4949 } ) . Single ( ) ;
5050 //The linq's OrderBy<TSource, TKey> has two generic types, which provided here
@@ -76,7 +76,7 @@ public static IOrderedQueryable<TSource> CustomOrderByDescending<TSource>(
7676 . Where ( m =>
7777 {
7878 var parameters = m . GetParameters ( ) . ToList ( ) ;
79- //Put more restriction here to ensure selecting the right overload
79+ //Put more restriction here to ensure selecting the right overload
8080 return parameters . Count == 2 ; //overload that has 2 parameters
8181 } ) . Single ( ) ;
8282 //The linq's OrderByDescending<TSource, TKey> has two generic types, which provided here
@@ -129,53 +129,53 @@ public static IQueryable<TSource> CustomFiltering<TSource>(
129129
130130 // foreach on all fields on entity type and take only string type fields and fields, whose names were transmitted
131131 foreach ( var prop in typeof ( TSource ) . GetProperties ( ) . Where ( x =>
132- propertyNames . Contains ( x . Name ) && ( x . PropertyType == typeof ( string ) ||
133- x . PropertyType == typeof ( int ? ) ||
134- x . PropertyType == typeof ( DateTime ? ) ||
135- x . PropertyType == typeof ( int ) ||
136- x . PropertyType == typeof ( DateTime ) ) ) )
132+ propertyNames . Contains ( x . Name ) && ( x . PropertyType == typeof ( string ) ||
133+ x . PropertyType == typeof ( int ? ) ||
134+ x . PropertyType == typeof ( DateTime ? ) ||
135+ x . PropertyType == typeof ( int ) ||
136+ x . PropertyType == typeof ( DateTime ) ) ) )
137137 {
138- // x => x.propName
139138 var memberExpression = Expression . PropertyOrField ( parameter , prop . Name ) ;
140139
141- // if type prop not string - need to call ToString()
142- MethodCallExpression toStringCall ;
140+ MethodCallExpression toStringCall = null ;
143141 if ( prop . PropertyType == typeof ( DateTime ) )
144142 {
145- // x.propName.ToString()
146- toStringCall = Expression . Call ( memberExpression , dateTimeToStringMethod ) ;
143+ toStringCall = Expression . Call ( memberExpression , dateTimeToStringMethod ) ;
147144 }
148145 else if ( prop . PropertyType == typeof ( DateTime ? ) )
149146 {
150- // x.propName.ToString()
151147 toStringCall = Expression . Call ( memberExpression , nullebleDateTimeToStringMethod ) ;
152148 }
153149 else if ( prop . PropertyType == typeof ( int ? ) )
154150 {
155- // x.propName.ToString()
156151 toStringCall = Expression . Call ( memberExpression , nullebleIntToStringMethod ) ;
157152 }
158153 else if ( prop . PropertyType == typeof ( int ) )
159154 {
160- // x.propName.ToString()
161155 toStringCall = Expression . Call ( memberExpression , intToStringMethod ) ;
162156 }
163- else
164- {
165- // prop is string. not need call ToString()
166- toStringCall = null ;
167- }
168157
169- // string valueExpression = filter;
170158 var valueExpression = Expression . Constant ( filter . ToUpper ( ) , typeof ( string ) ) ;
171159
172- // x.propName(x.propName is string ? none : .ToString()).ToUpper()
173- var toUpperExpression = Expression . Call ( toStringCall == null ? memberExpression : toStringCall , toUpperMethod ) ;
174-
175- // x.propName(x.propName is string ? none : .ToString()).ToUpper().Contains(filter.ToUpper())
176- var containsExpression = Expression . Call ( toUpperExpression , containsMethod , valueExpression ) ;
177-
178- expressions . Add ( containsExpression ) ;
160+ if ( prop . PropertyType == typeof ( string ) )
161+ {
162+ // x.propName != null
163+ var notNull = Expression . NotEqual ( memberExpression , Expression . Constant ( null , typeof ( string ) ) ) ;
164+ // x.propName.ToUpper()
165+ var toUpperExpression = Expression . Call ( memberExpression , toUpperMethod ) ;
166+ // x.propName.ToUpper().Contains(filter.ToUpper())
167+ var containsExpression = Expression . Call ( toUpperExpression , containsMethod , valueExpression ) ;
168+ // x.propName != null && x.propName.ToUpper().Contains(filter.ToUpper())
169+ var safeContains = Expression . AndAlso ( notNull , containsExpression ) ;
170+ expressions . Add ( safeContains ) ;
171+ }
172+ else
173+ {
174+ // x.propName.ToString().ToUpper().Contains(filter.ToUpper())
175+ var toUpperExpression = Expression . Call ( toStringCall , toUpperMethod ) ;
176+ var containsExpression = Expression . Call ( toUpperExpression , containsMethod , valueExpression ) ;
177+ expressions . Add ( containsExpression ) ;
178+ }
179179 }
180180
181181 // if not need filtration - return
@@ -190,7 +190,7 @@ public static IQueryable<TSource> CustomFiltering<TSource>(
190190 // and start from 1 add contains like x.Name.Contains(filter) || x.Description.Contains(filter) || ...
191191 for ( var i = 1 ; i < expressions . Count ; i ++ )
192192 {
193- orExpression = Expression . OrElse ( orExpression , expressions [ i ] ) ;
193+ orExpression = Expression . Or ( orExpression , expressions [ i ] ) ;
194194 }
195195
196196 // x.Name or x.Description - **example**
0 commit comments