如何将变量传递给谓词表达式?
How to pass a variable to predicate expression?
我正在动态创建 Expression<Func<Entity, bool>>
表达式树:
int id = ...;
Expression<Func<Entity, int>> keySelector = e => e.Id;
BinaryExpression equals = Expression.Equal(
keySelector.Body,
Expression.Constant(id, keySelector.Body.Type)); //replace this with a variable
var predicate = Expression.Lambda<Func<Entity, bool>>(equals, keySelector.Parameters[0]);
相当于 e => e.Id == 1
.
如何传递变量而不是常量:e => e.Id == id
您需要将常量更改为可以更改 属性 的内容:
class IDHolder
{
public int Id { get; set; }
}
现在您将表达式绑定到 IDHolder 的实例,如下所示:
var idHolder = new IDHolder { Id = 0 };
Expression<Func<Entity, int>> keySelector = e => e.Id;
BinaryExpression equals = Expression.Equal(
keySelector.Body,
Expression.Property(
Expression.Constant(idHolder, typeof(IDHolder)),
nameof(IDHolder.Id))
);
var predicate = Expression.Lambda<Func<Entity, bool>>(equals, keySelector.Parameters[0]);
谓词变得稍微复杂一些,但不会使 EF 中断:
x => x.Id == idHandler.Id
您可以通过编译谓词和 运行 更改 Id 和实体的简单测试来测试它:
var func = predicate.Compile();
idHolder.Id = 5;
Console.WriteLine(func(new Entity { Id = 0 }).ToString()); // false
Console.WriteLine(func(new Entity { Id = 5 }).ToString()); // true
idHolder.Id = 6;
Console.WriteLine(func(new Entity { Id = 6 }).ToString()); // true
请注意,此方法不是线程安全的,如果您缓存谓词和 idHolder 并将其用于 Web api 项目或任何可能同时使用此谓词的项目,将会导致奇怪的行为。要自动翻译请求中的某些条件,最好在每次需要在 EF 中使用它时创建表达式。创建表达式时不会对性能造成重大影响;昂贵的操作是编译,而 EF 永远不会这样做。
或者我误解了您的问题,您只需要一种方法来更改 id 的值,正如@Jochem Van Hespen 所建议的,您需要一个函数:
public Expression<Func<Entity,bool>> GetPredicate(int id){
Expression<Func<Entity, int>> keySelector = e => e.Id;
BinaryExpression equals = Expression.Equal(
keySelector.Body,
Expression.Constant(id, keySelector.Body.Type));
var predicate = Expression.Lambda<Func<Entity, bool>>(equals, keySelector.Parameters[0]);
return predicate;
}
你可以这样使用它:
_dbContext.Set<Entity>().Where(GetPredicate(4))
我正在动态创建 Expression<Func<Entity, bool>>
表达式树:
int id = ...;
Expression<Func<Entity, int>> keySelector = e => e.Id;
BinaryExpression equals = Expression.Equal(
keySelector.Body,
Expression.Constant(id, keySelector.Body.Type)); //replace this with a variable
var predicate = Expression.Lambda<Func<Entity, bool>>(equals, keySelector.Parameters[0]);
相当于 e => e.Id == 1
.
如何传递变量而不是常量:e => e.Id == id
您需要将常量更改为可以更改 属性 的内容:
class IDHolder
{
public int Id { get; set; }
}
现在您将表达式绑定到 IDHolder 的实例,如下所示:
var idHolder = new IDHolder { Id = 0 };
Expression<Func<Entity, int>> keySelector = e => e.Id;
BinaryExpression equals = Expression.Equal(
keySelector.Body,
Expression.Property(
Expression.Constant(idHolder, typeof(IDHolder)),
nameof(IDHolder.Id))
);
var predicate = Expression.Lambda<Func<Entity, bool>>(equals, keySelector.Parameters[0]);
谓词变得稍微复杂一些,但不会使 EF 中断:
x => x.Id == idHandler.Id
您可以通过编译谓词和 运行 更改 Id 和实体的简单测试来测试它:
var func = predicate.Compile();
idHolder.Id = 5;
Console.WriteLine(func(new Entity { Id = 0 }).ToString()); // false
Console.WriteLine(func(new Entity { Id = 5 }).ToString()); // true
idHolder.Id = 6;
Console.WriteLine(func(new Entity { Id = 6 }).ToString()); // true
请注意,此方法不是线程安全的,如果您缓存谓词和 idHolder 并将其用于 Web api 项目或任何可能同时使用此谓词的项目,将会导致奇怪的行为。要自动翻译请求中的某些条件,最好在每次需要在 EF 中使用它时创建表达式。创建表达式时不会对性能造成重大影响;昂贵的操作是编译,而 EF 永远不会这样做。
或者我误解了您的问题,您只需要一种方法来更改 id 的值,正如@Jochem Van Hespen 所建议的,您需要一个函数:
public Expression<Func<Entity,bool>> GetPredicate(int id){
Expression<Func<Entity, int>> keySelector = e => e.Id;
BinaryExpression equals = Expression.Equal(
keySelector.Body,
Expression.Constant(id, keySelector.Body.Type));
var predicate = Expression.Lambda<Func<Entity, bool>>(equals, keySelector.Parameters[0]);
return predicate;
}
你可以这样使用它:
_dbContext.Set<Entity>().Where(GetPredicate(4))