Ядро EF динамически фильтрует из списка

#c# #asp.net #entity-framework #.net-core #entity-framework-core

#c# #asp.net #entity-framework #.net-ядро #сущность-фреймворк-ядро

Вопрос:

Я работаю над созданием общего динамического фильтра для интерфейсной таблицы. Идея в том, что у каждого столбца будет фильтр, в котором вы можете выбирать значения этого столбца. Имена столбцов должны быть полностью динамическими и выбранными значениями. Мы используем .NET 5 и EF Core 5.

SQL-запрос, который я хочу, это:

 
SELECT * 
FROM Users
WHERE externalId IN ('1234', '5678');

 

Модели:

 
public class ColumnFilter
    {
        [Required]
        public string Name { get; set; } // column name
        public List<string> SelectedValues { get; set; } = new List<string>(); // values selected in this column
    }

public class User {
        public string Name { get; set; } 
        public string ExternalId { get; set; } 
}

 

Упрощенный код:

 
//columnfilter really comes from API request
var columnFilter = new ColumnFilter{
Name = "ExternalId",
SelectedValues = new List<string>{ "1234", "5678" }
};

var queryable = _context.Users.AsNoTracking();

queryable = queryable.Where(f => columnFilter.SelectedValues.Contains(EF.Property<string>(f, columnFilter.Name)));

var values = await queryable.ToListAsync(); // 0 results

 

Ядро EF генерирует этот запрос:

       SELECT *
      FROM [Users] AS [u]
      WHERE 0 = 1
 

Как мне заставить это работать динамически?

Комментарии:

1. Я думаю, что вам следует взглянуть Dynamic LINQ library , это должно решить проблему для вас. Создайте выражение динамически

2. Безопасна ли эта библиотека от sql-инъекций?

3. Вы просто можете динамически создавать выражения, решение @Svyatoslav Danyliv также должно быть очень хорошим решением

Ответ №1:

Это образец, использующий строковые значения:

 var queryable = _context.Users.AsNoTracking();

queryable = queryable.FilterDynamic(columnFilter.Name, columnFilter.SelectedValues);

 
 public static class QueryableExtensions
{
    public static IQueryable<T> FilterDynamic<T>(this IQueryable<T> query, string fieldName, ICollection<string> values)
    {
        var param = Expression.Parameter(typeof(T), "e");
        var prop = Expression.PropertyOrField(param, fieldName);
        var body = Expression.Call(typeof(Enumerable), "Contains", new[] {typeof(string)},
            Expression.Constant(values), prop);
        var predicate = Expression.Lambda<Func<T, bool>>(body, param);
        return query.Where(predicate);
    }
}
 

Ответ №2:

Решение, которое у меня было, действительно работает. У меня был какой-то другой код, который вызывал проблему.