C# 将lambda表达式移动到实体框架中的静态扩展方法

C# 将lambda表达式移动到实体框架中的静态扩展方法,c#,linq-to-sql,entity-framework-core,C#,Linq To Sql,Entity Framework Core,我正在尝试将实体框架查询的以下行重构为通用静态扩展方法: dbContext.Employees .Where(e => permissionResolver.AuthorizedUsers.Select(p => p.Id).Contains(e.Id)) .OrderBy(...) PermissionResolver只是一个实例,我从中收到一个ID列表,与当前记录中存储的用户ID进行比较。它可以完美地编译成SQL语句,其中Id位于(..)

我正在尝试将实体框架查询的以下行重构为通用静态扩展方法:

dbContext.Employees
         .Where(e => permissionResolver.AuthorizedUsers.Select(p => p.Id).Contains(e.Id))
         .OrderBy(...)
PermissionResolver
只是一个实例,我从中收到一个ID列表,与当前记录中存储的用户ID进行比较。它可以完美地编译成SQL语句
,其中Id位于(..)

现在,我正在尝试为
IQueryable
创建一个扩展方法,可以用于任何类型的记录,我只想传入一个存储所有者ID的属性

这就是我想到的:

public static IQueryable<T> AuthorizedRecords<T>(this IQueryable<T> query, Expression<Func<T, Int32>> property, IPermissionResolver permissionResolver)
{
    Expression<Func<T, Boolean>> idIsAuthorized = entity => permissionResolver.AuthorizedUsers.Select(e => e.Id).ToList().Contains(property.Compile()(entity));                

    return query.Where(idIsAuthorized);
}
公共静态IQueryable AuthorizedRecords(此IQueryable查询、表达式属性、IPermissionResolver permissionResolver)
{
表达式idIsAuthorized=entity=>permissionResolver.AuthorizedUsers.Select(e=>e.Id).ToList()包含(property.Compile()(entity));
返回查询。其中(idIsAuthorized);
}
我收到一个运行时错误,该表达式无法转换为SQL


如何将属性表达式与主查询表达式组合,以便将其正确转换为SQL?有更好的方法重写查询表达式吗?

简单的回答是,您不能在实体框架查询中使用自定义扩展方法。在hood实体框架下,将表达式树
expression
解析为sql查询。似乎不可能将任何可能的扩展方法转换为sql,因此它们支持有限的Linq方法集来正确地转换它。有关表达式树的一些有用信息:。
为了简化查询,您可以使用
任何
方法进行重构,如下所示:

dbContext.Employees
    .Where(e => permissionResolver.AuthorizedUsers.Any(u => u.Id == e.Id))
    .OrderBy(...
property.Compile()
将表达式树转换为委托,此委托无法正确转换回表达式树/SQL

您需要这样构造表达式树:

var ids = permissionResolver.AuthorizedUsers.Select(e => e.Id).ToList().AsEnumerable();
// method Enumerable.Contains<int>()
var methodContains = typeof(System.Linq.Enumerable).GetMethods()
    .Where(m => m.Name == "Contains" && m.GetParameters().Length == 2)
    .First()
    .MakeGenericMethod(typeof(int));

 var lambdaParam = property.Parameters.Single();
 var lambda = Expression.Lambda(
     Expression.Call(
         methodContains,
         Expression.Constant(ids), 
         property.Body),
     lambdaParam
 );
 var predicate = (Expression<Func<T, bool>>)lambda;
 return query.Where(predicate);
var Id=permissionResolver.AuthorizedUsers.Select(e=>e.Id.ToList().AsEnumerable();
//方法Enumerable.Contains()
var methodContains=typeof(System.Linq.Enumerable).GetMethods()
.Where(m=>m.Name==“包含”&&m.GetParameters().Length==2)
.First()
.MakeGenericMethod(typeof(int));
var lambdaParam=property.Parameters.Single();
var lambda=表达式.lambda(
表情,打电话(
方法包含,
表达式.常量(ids),
财产,机构),,
lambdaParam
);
var谓词=(表达式)lambda;
返回query.Where(谓词);

对于
属性
参数而不是
表达式
使用普通的
Func
怎么样?没有成功,运行时会引发相同的异常。也许调用表达式内部的函数时出错了。我用了
。包含(属性(实体))