@ErichZann

Это оптимальный способ фильтрации записей из таблицы с помощью Entity Framework?

Добрый день
У меня есть таблица Products. Данные для фильтрации поступают из комбобоксов фронтенда, где пользователь может выбрать несколько значений для одного комбобокса (например, 3 разных ProductGroups + 2 разных Supplier). Хотел спросить, оптимальна ли моя реализация, или я что-то упустил? Ниже код Action из контроллера и самой фильтрации. Спасибо.

[HttpPut("[action]")]
    public async Task<IQueryable<ProductDto>> Put([FromBody] ProductsQueryAll query)
    {
        var response = await _mediator.Send(query);
        return response;
    }


public class ProductsQueryAll : IRequest<IQueryable<ProductDto>>
    {
        public string[] ProductGroups { get; set; }
        public int[] SupplierIds { get; set; }
        public string[] Categories { get; set; }
    }

    public class ProductsQueryAllHandler : IRequestHandler<ProductsQueryAll, IQueryable<ProductDto>>
    {
        private readonly DbContext _dbContext;
        private readonly IMapper _mapper;

        public ProductsQueryAllHandler(DbContext dbContext, IMapper mapper)
        {
            _dbContext = dbContext;
            _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
        }

        public Task<IQueryable<ProductDto>> Handle(ProductsQueryAll request, CancellationToken cancellationToken)
        {
            var predicate = PredicateBuilder.True<ProductDm>();
            if (request.ProductGroups?.Length > 0)
            {
                predicate = predicate.And(x => request.ProductGroups.Any(y => y == x.ProductGroup));
            }
            if (request.SupplierIds?.Length > 0)
            {
                predicate = predicate.And(x => request.SupplierIds.Any(y => y == x.SupplierId));
            }
            if (request.Categories?.Length > 0)
            {
                predicate = predicate.And(x => request.Categories.Any( y => y == x.Category));
            }


            var entityList = _dbContext.Products
                .AsNoTracking()
                .Where(predicate);

            return Task.FromResult(_mapper.ProjectTo<ProductDto>(entityList));
        }
    }
  • Вопрос задан
  • 151 просмотр
Решения вопроса 1
igolets
@igolets
Программист C#, MSSQL
Я как-то обычно пишу код чуть проще:
var query = _dbContext.Products.AsQueryable();
            if (request.ProductGroups?.Length > 0)
            {
                query = query.Where(x => request.ProductGroups.Any(y => y == x.ProductGroup));
            }
            if (request.SupplierIds?.Length > 0)
            {
                query = query.Where(x => request.SupplierIds.Any(y => y == x.SupplierId));
            }
            if (request.Categories?.Length > 0)
            {
                query = query.Where(x => request.Categories.Any( y => y == x.Category));
            }


            return Task.FromResult(_mapper.ProjectTo<ProductDto>(query));


Общие замечания к коду:
1. Есть ограничения по размеру запроса, если ProductGroups и Categories будут иметь длинные названия, могут быть исключения в рантайме
2. Надо внимательно подумать на счёт ProductGroups и Categories и используемого движка БД — на предмет CaseSensitive и CaseInsensitive сравнений. Могут тоже быть приколы — когда запись из БД вернулась (там CaseInsensitive), а какой-то код на стороне C# не принял эту запись и упал (CaseSensitive).
3. Соответственно, как предложение на подумать — нормализовать ProductGroups и Categories в отдельные таблицы ;)
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы