使用表达式创建 EF 查询扩展

问题描述 投票:0回答:1

我想写一个IQueryable的扩展方法来过滤掉一些实体。此方法应具有类型为 Expression> 的参数,用于过滤实体。

这是我的尝试,我不知道为什么这不起作用。有什么想法吗?

public static IQueryable<T> AddDefaultQuery<T>(this IQueryable<T> query, Expression<Func<T, int>> countryId, ApplicationDbContext db, ClaimsPrincipal claimsPrincipal)
{
    if (claimsPrincipal.IsEppRole()) {
        var userCountryIds = db.UserCountry.Where(uc => uc.UserId == LoginUser.GetUserID(claimsPrincipal)).Select(uc => uc.CountryId);
        query = query.Where(q => userCountryIds.Contains(countryId.Compile()(q)));
    }
    return query;
}

错误是:

发生异常:CLR/System.InvalidOperationException 抛出的异常:Microsoft.EntityFrameworkCore.dll 中的“System.InvalidOperationException”:“LINQ 表达式”DbSet() .Where(a => a.Deleted == False) .Where(a => __userCountryIds_0.Contains(__Compile_1.Invoke(a)))' 无法翻译。以可以翻译的形式重写查询,或者通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用来显式切换到客户端评估。有关详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2101038。'

c# entity-framework linq expression iqueryable
1个回答
0
投票

最近有同样的问题。问题出在这里:

Where(q => userCountryIds.Contains(countryId.Compile()(q)))
.

我了解到

Func
inside
Contains
inside
Where
并不是 LINQ to SQL 转换器可以处理的。正如我所注意到的,compiled 表达式也没有转换为 SQL,它们将在查询 SQL 后执行,这可能会导致性能下降。

我猜你有这样的表情

 Expression<Func<T, int>> expression = foo => foo.Id

现在如果我们创建一个这样的表达式:

//don't forget to put a constraint on T like 
//"where T : IHasId" or something like that
public static Expression<Func<T, bool>> BuildExpression<T>(ApplicationDbContext db, ClaimsPrincipal claimsPrincipal)
{
    var userCountryIds = db.UserCountry
        //this one might also not be translated to SQL
        //because it uses function that is not supported by SQL
        .Where(uc => uc.UserId == LoginUser.GetUserID(claimsPrincipal))
        .Select(uc => uc.CountryId)
        .ToList();
    var isEppRole = claimsPrincipal.IsEppRole();
    return foo => !isEppRole || userCountryIds.Contains(foo.Id);
}

然后在你的扩展方法中

public IQueryable<T> AddDefaultQuery<T>(this IQueryable<T> query, ApplicationDbContext db, ClaimsPrincipal claimsPrincipal)
{
    var exp = BuildExpression<T>(db, claimsPrincipal);
    //no lambdas, nothing else except the expression itself
    return query.Where(exp);
}

这种方法对我有帮助,希望它对你也有帮助,或者至少会为你指明正确的方向

© www.soinside.com 2019 - 2024. All rights reserved.