Reputation: 725
Using the Dynamic where here
Entity Framework Core Dynamic Where Clause
I am able to have a where on any column in any table, accessed by property name, using an Entity Framework typed repository pattern. However this will AND any time there is more than one where, when it needs to be an OR WHERE when there is more than one where on a column.
How must this be modified to do an OR WHERE when there is more than one property value for a property name?
An array of property names and property value loops through calling this method.
private static IQueryable<T> AddWhereClause( IQueryable<T> query, string propName, string propValue )
{
ParameterExpression parameterExpression = Expression.Parameter( typeof( T ), "e" );
Expression makePropPath = MakePropPath( parameterExpression, propName );
ConstantExpression value = null;
string dataPropertyType = typeof( T ).GetProperties()
.FirstOrDefault( pi => pi.Name == propName )?.PropertyType.FullName;
if (dataPropertyType.Contains( "System.String" ))
{
value = Expression.Constant( propValue, typeof( string ) );
}
else if (dataPropertyType.Contains( "System.Int" ))
{
int? valueCast = Convert.ToInt32( propValue );
value = Expression.Constant( valueCast, typeof( int? ) );
}
else if (dataPropertyType.Contains( "System.Double" ))
{
double? valueCast = Convert.ToDouble( propValue );
value = Expression.Constant( valueCast, typeof( double? ) );
}
else if (dataPropertyType.Contains( "System.Boolean" ))
{
bool? valueCast = Convert.ToBoolean( propValue );
value = Expression.Constant( valueCast, typeof( bool? ) );
}
BinaryExpression body = Expression.Equal( makePropPath, value );
Expression<Func<T, bool>> predicateLambda = Expression.Lambda<Func<T, bool>>( body, parameterExpression );
return query.Where( predicateLambda );
}
However
Upvotes: 0
Views: 60
Reputation: 725
Seems predicate builder was exactly designed to add the predicate lambdas properly with a WHERE and a OR WHERE, more specifically an IN (value1, value2). The caveat is that the same predicate builder needs to be used for each column.
First the columns need to get grouped, by propName, so all the propValues are added and applied together. Then create the predicate builder of type T. Then loop through the selectFilters with the propName and propValue, adding each of the predicates, with a predicate.Or(). Finally, add it to the IQueryable.
foreach (IGrouping<string, SelectFilter> selectFiltersGroup in selectFiltersGroups)
{
string propName = string.Concat( selectFiltersGroup.Key[ 0 ].ToString().ToUpper(), selectFiltersGroup.Key.AsSpan( 1 ) );
List<SelectFilter> selectFilterList = selectFiltersGroup.ToList();
ExpressionStarter<T> predicate = LinqKit.PredicateBuilder.New<T>( false );
foreach (SelectFilter selectFilter in selectFilterList)
{
Expression<Func<T, bool>> predicateLambda = GetPredicateLambda( propName, selectFilter.Value );
predicate.Or( predicateLambda );
}
query = query.Where( predicate );
}
Upvotes: 0