Поиск по ряду критериев
Всем привет. Подскажите пожалуйста как можно сделать поиск с группой критериев. У меня есть таблица с информацией о человеке и еще парой свойств таких как телефон и дата. Как сделать так, чтобы фильтр переваривал все поля запроса сразу. Т.е. сделать поиск по ряду критериев.
Сейчас имеется такой код. Идею с Func подсмотрел где-то по форумам, но она у меня не срабатывает. В консоль ничего не падает.
public class GetBlackListQueryHandler : IRequestHandler<GetBlackListRequest, IOrderedEnumerable<BlackList>>
{
readonly IReadonlyRepository<BlackListEntity> _readonlyRepository;
public GetBlackListQueryHandler(
IReadonlyRepository<BlackListEntity> readonlyRepository)
{
_readonlyRepository = readonlyRepository;
}
public async Task<IOrderedEnumerable<BlackList>> Handle(GetBlackListRequest request, CancellationToken cancellationToken)
{
IOrderedEnumerable<BlackList> x = null;
var result = await _readonlyRepository.GetAsync(cancellationToken);
var dataForSort = result.Value.Select(x => new BlackList
{
ItemId = x.Id,
LastName = x.LastName,
FirstName = x.FirstName,
MiddleName = x.MiddleName,
PhoneNumber = x.PhoneNumber,
CreateDate = x.CreateDate,
}).ToList();
string? lastName = request.LastNameS,
firstName = request.FirstNameS,
middleName = request.MiddleNameS,
phone = request.PhoneS;
DateTime? date = null;
bool filterByLastName = true,
filterByFirstName = false,
filterByMiddleName = false,
filterByPhone = false,
filterByDate = true;
Func<BlackList, bool> predicateByLastName = x => x.LastName == lastName;
Func<BlackList, bool> predicateByFirstName = x => x.FirstName == firstName;
Func<BlackList, bool> predicateByMiddleName = x => x.MiddleName == middleName;
Func<BlackList, bool> predicateByPhone = x => x.PhoneNumber == phone;
Func<BlackList, bool> predicateByDate = x => x.CreateDate == date;
Func<BlackList, bool> mainPredicate = x => (!filterByLastName || predicateByLastName(x))
&& (!filterByFirstName || predicateByFirstName(x))
&& (!filterByMiddleName || predicateByMiddleName(x))
&& (!filterByPhone || predicateByPhone(x))
&& (!filterByDate || predicateByDate(x));
foreach (var entity in dataForSort.Where(mainPredicate))
{
Console.WriteLine(entity);
}
switch (request.SortBy)
{
case "LastName":
x = dataForSort.OrderBy(x => x.LastName);
break;
case "LastNameDesc":
x = dataForSort.OrderByDescending(x => x.LastName);
break;
case "FirstName":
x = dataForSort.OrderBy(x => x.FirstName);
break;
case "FirstNameDesc":
x = dataForSort.OrderByDescending(x => x.FirstName);
break;
case "MiddleName":
x = dataForSort.OrderBy(x => x.MiddleName);
break;
case "MiddleNameDesc":
x = dataForSort.OrderByDescending(x => x.MiddleName);
break;
case "PhoneNumber":
x = dataForSort.OrderBy(x => x.PhoneNumber);
break;
case "PhoneNumberDesc":
x = dataForSort.OrderByDescending(x => x.PhoneNumber);
break;
case "CreateDate":
x = dataForSort.OrderBy(x => x.CreateDate);
break;
case "CreateDateDesc":
x = dataForSort.OrderByDescending(x => x.CreateDate);
break;
}
return x;
}
}
BlackList моделька
public class BlackList
{
public Guid ItemId { get; set; }
public string? LastName { get; set; }
public string? FirstName { get; set; }
public string? MiddleName { get; set; }
public string? PhoneNumber { get; set; }
public DateTime CreateDate { get; set; }
}
BlackListRequest
public string AccessToken { get; set; } = default!;
public string SortBy { get; set; } = "CreateDate";
public string? LastNameS { get; set; }
public string? FirstNameS { get; set; }
public string? MiddleNameS { get; set; }
public string? DateS { get; set; }
public string? PhoneS { get; set; }
Верия EF Core 6.0.6
Метод из репозитория
Task<Result<IEnumerable<T>>> GetAsync(CancellationToken cancellationToken,
Expression<Func<T, bool>>? filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>>? sort = null,
string? include = null);
реализацию инклюда
public static IQueryable<T> AddIncludes<T>(this IQueryable<T> query, string? include = null)
where T : class
{
if (!string.IsNullOrWhiteSpace(include))
{
foreach (var i in include.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(i);
}
}
return query;
}
Ответы (1 шт):
Вызов метода репозитория может выглядеть следующим образом:
var result = await _readonlyRepository.GetAsync(
cancellationToken,
x => x.FirstName.StartsWith("A"),
query => query.OrderBy(x => x.LastName),
"Childs,Items");
Вначале идёт токен отмены, затем выражение фильтрации, затем выражение сортировки и последним - имя навигационного свойства-коллекции.
Вообще, CancellationToken всегда должен идти последним параметром.
Вы так и не показали определение GetBlackListRequest.
Судя по его использованию, код метода Handle может выглядеть так:
Expression<Func<BlackListEntity, bool>>? filter = null;
if (request.FirstNameS != null)
filter = x => x.FirstName == request.FirstNameS;
else if (request.LastNameS != null)
filter = x => x.LastName == request.LastNameS;
Func<IQueryable<BlackListEntity>, IOrderedQueryable<BlackListEntity>>? sort = null;
if (request.SortBy != null)
{
string sortProperty = request.SortBy;
if (sortProperty.EndsWith("Desc"))
{
sortProperty = sortProperty[..^4];
sort = query => query.OrderByDescending(x => EF.Property<BlackListEntity>(x, sortProperty));
}
else
{
sort = query => query.OrderBy(x => EF.Property<BlackListEntity>(x, sortProperty));
}
}
var result = await _readonlyRepository.GetAsync(
cancellationToken, filter, sort, request.Include);
Мне неведомо, как именно планируется задавать и использовать фильтр. Поэтому лишь базовый пример.
Вы там пытаетесь конструировать mainPredicate - да, нужно что-то такое. Получается сложно. Вероятно, следует изменить GetBlackListRequest - это же ваша часть кода?
И в самом конце:
var dataForSort = result.Value
.Select(x => new BlackList
{
// маппинг свойств
})
.ToList();
return dataForSort;