Задать вопрос
@hax
junior developer

Как можно объединить два Expression'a в один для получения данных из Entity Framework Core?

Привет! У меня есть два экспрешена с условиями, которые я хочу объединить в один экспрешен и скормить в Entity Framework Core.

Expression<Func<Device, bool>> deviceTypeFilter = d => d.DeviceTypes == DeviceTypes.Camera;
Expression<Func<Device, bool>> geolocationFilter = d => d.Latitude == 23.2;
 
var finalCriteria = Expression.AndAlso(deviceTypeFilter.Body, geolocationFilter.Body);
var lambda = Expression.Lambda<Func<Device, bool>>(finalCriteria, Expression.Parameter(typeof(Device)));
 
IQueryable<Device> query = this.Entities;
query = lambda != null ? query.Where(lambda) : query;
 
return await query.AsNoTracking().ToListAsync();


Но у меня этот код не работает. Падает с ошибкой:
'The LINQ expression 'DbSet
.Where(d => (int)d.DeviceTypes == 1 && d.Latitude == 23,2)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'


Если передавать экспрешены по отдельности, то всё работает. Значит я как-то не правильно объединяют эти экспрешены? В чём может быть ошибка?
  • Вопрос задан
  • 870 просмотров
Подписаться 1 Средний Комментировать
Решения вопроса 2
sarapinit
@sarapinit Куратор тега C#
Точу водой камень
Если вы просто добавите к своему запросу Where на каждое выражение то это как раз будет логическое «И». Я обычно так делаю.

Пример кода:
Task<Device[]> FilteredDevices(params Expression<Func<Device, bool>> filters)
{
    IQueryable<Device> query = this.Entities;
    foreach(var filter in filters)
    {
        query = query.Where(filter);
    }
    return query.AsNoTracking().ToArrayAsync();
}


PS
Но если хотете заморочиться по экспрешенам, то вот вам доклад
Ответ написан
@hax Автор вопроса
junior developer
Спасибо Илья за ссылку на доклад. Благодаря нему я нашёл ошибку (оказывается нельзя просто так взять и соединить два экспрешена). Накидал небольшой метод, который соединяет два экспрешена логическим "И" (&&):
public static Expression<T> Combine<T>(
    Expression<T> firstExpression,
    Expression<T> secondExpression)
{
    if (firstExpression is null)
    {
        return secondExpression;
    }

    if (secondExpression is null)
    {
        return firstExpression;
    }

    var invokedExpression = Expression.Invoke(
        secondExpression,
        firstExpression.Parameters);

    var combinedExpression = Expression.AndAlso(firstExpression.Body, invokedExpression);

    return Expression.Lambda<T>(combinedExpression, firstExpression.Parameters);
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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