#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:
Решение, которое у меня было, действительно работает. У меня был какой-то другой код, который вызывал проблему.