Самый простой способ - использовать switch
с предопределенными именами свойств. Я не рекомендую разрешать пользователям указывать точное свойство или столбец для фильтрации, потому что это приведет к рискам конфиденциальности и дырам в безопасности (например, поскольку это позволит пользователям искать других пользователей по электронной почте, имени или паролю без вашего ведома) .
private async Task<List<UserModel>> SearchUsersAsync( String fieldname, String value )
{
IQueryable<User> q = this.Users;
switch( fieldName )
{
case nameof(UserModel.Name):
q = q.Where( u => u.Name == value );
break;
case nameof(UserModel.Bio):
q = q.Where( u => u.Bio.Contains( value ) );
break;
case nameof(UserModel.Email):
q = q.Where( u => u.Email == value );
break;
default:
throw new ArgumentOutOfRangeException( "Unsupported property name." );
}
List<User> users = await q
.OrderBy( u => u.UserId )
.ToListAsync()
.ConfigureAwait(false);
List<UserModel> userViewModels = users
.Select( u => UserModel.FromUserEntity( u ) )
.ToList();
return userViewModels;
}
Используя этот подход, вы можете избежать ArgumentOutOfRangeException
в нормальном потоке, используя вместо него enum
, который может быть параметром маршрута (а также поддерживать определяемое пользователем упорядочивание!):
enum UserProperty
{
None,
Name,
Bio,
Email
}
internal static class QueryExtensions
{
public static IQueryable<User> WhereProperty( this IQueryable<User> q, UserProperty prop, String value )
{
if( String.IsNullOrWhiteSpace( value ) ) return q;
switch( prop)
{
case UserProperty.None:
return q;
case UserProperty.Name:
return q.Where( u => u.Name == value );
caseUserProperty.Bio:
return q.Where( u => u.Bio.Contains( value ) );
case UserProperty.Email:
return q.Where( u => u.Email == value );
default:
throw new ArgumentOutOfRangeException( "Unsupported property name." );
}
}
public static IOrderedQueryable<User> OrderByProperty( this IQueryable<User> q, UserProperty prop, Boolean asc )
{
switch( prop )
{
case UserProperty.None:
return q;
case UserProperty.Name:
return asc ? q.OrderBy( u => u.Name ) : q.OrderByDescending( u => u.Name );
case UserProperty.Bio:
return asc ? q.OrderBy( u => u.Bio ) : q.OrderByDescending( u => u.Bio );
case UserProperty.Email:
return asc ? q.OrderBy( u => u.Email ) : q.OrderByDescending( u => u.Email );
default:
throw new ArgumentOutOfRangeException( "Unsupported property name." );
}
}
}
И эти методы расширения можно использовать так:
private async Task<List<UserModel>> SearchUsersAsync( UserProperty filterProp = UserProperty.None, String filterValue = null, UserProperty sortProp = UserProperty.None, Boolean sortAscending = true )
{
List<User> users = await this.Users
.WhereProperty( filterProp, filterValue )
.OrderByProperty( sortProp, sortAscending )
.ToListAsync()
.ConfigureAwait(false);
List<UserModel> userViewModels = users
.Select( u => UserModel.FromUserEntity( u ) )
.ToList();
return userViewModels;
}