gpt4 book ai didi

c# - 组合多个表达式树

转载 作者:太空狗 更新时间:2023-10-29 23:21:25 25 4
gpt4 key购买 nike

我收到以下错误

The parameter 'p' was not bound in the specified LINQ to Entities query expression.

我理解这个问题(ParameterExpression 的同一个实例应该与树中的所有表达式一起使用)并尝试使用我在网上找到的解决方案,但没有成功。

这是我的方法

private void SeedEntity<TEntity>(DatabaseContext context, ref TEntity entity, params Expression<Func<TEntity, object>>[] identifierExpressions) where TEntity : class
{
Expression<Func<TEntity, bool>> allExpresions = null;

var parameters = identifierExpressions.SelectMany(x => x.Parameters).GroupBy(x => x.Name).Select(p => p.First()).ToList();

foreach (Expression<Func<TEntity, object>> identifierExpression in identifierExpressions)
{
Func<TEntity, object> vv = identifierExpression.Compile();
object constant = vv(entity);

ConstantExpression constExp = Expression.Constant(constant, typeof(object));
BinaryExpression equalExpression1 = Expression.Equal(identifierExpression.Body, constExp);
Expression<Func<TEntity, bool>> equalExpression2 = Expression.Lambda<Func<TEntity, bool>>(equalExpression1, parameters);

if (allExpresions == null)
{
allExpresions = equalExpression2;
}
else
{
BinaryExpression bin = Expression.And(allExpresions.Body, equalExpression2.Body);
allExpresions = Expression.Lambda<Func<TEntity, bool>>(bin, parameters);
}
}

TEntity existingEntity = null;
if (allExpresions != null)
{
existingEntity = context.Set<TEntity>().FirstOrDefault(allExpresions);
}

if (existingEntity == null)
{
context.Set<TEntity>().Add(entity);
}
else
{
entity = existingEntity;
}
}

它根据许多属性生成用于查找实体的表达式。

它对单个表达式工作正常,只有在传递多个时才会出现错误。

这样调用:

SeedEntity(context, ref e, p=> p.Name);//Works
SeedEntity(context, ref e, p=> p.Name, p=> p.Age);//Fails

它会生成类似于我执行以下操作的内容:

context.Set<TEntity>().FirstOrDefault(p=>p.Name == e.Name && p.Age == e.Age);

将 e.Name && e.Age 替换为 ConstantExpression

你可以在上面的方法中看到我获取所有唯一参数并将它们存储在 parameters 中在顶部,然后在整个过程中使用相同的变量。这是开始,但随后我需要替换每个 Expression<Func<TEntity, bool>> 中的参数实例。作为 params 传入数组,这是我失败的地方。

我已经尝试枚举表达式并使用 .Update()传入参数的方法

我还尝试了使用 ExpressionVisitor 的解决方案

public class ExpressionSubstitute : ExpressionVisitor
{
public readonly Expression from, to;
public ExpressionSubstitute(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
if (node == from) return to;
return base.Visit(node);
}
}

public static class ExpressionSubstituteExtentions
{
public static Expression<Func<TEntity, TReturnType>> RewireLambdaExpression<TEntity, TReturnType>(Expression<Func<TEntity, TReturnType>> expression, ParameterExpression newLambdaParameter)
{
var newExp = new ExpressionSubstitute(expression.Parameters.Single(), newLambdaParameter).Visit(expression);
return (Expression<Func<TEntity, TReturnType>>)newExp;
}
}

最佳答案

你真的很接近。我看不到您的 parameters 变量的意义。按名称对它们进行分组是错误的。为什么不直接传递表达式中的参数呢?必要时再去拜访。您的访客代码没问题。

    private static void SeedEntity<TEntity>(DbContext context, ref TEntity entity, params Expression<Func<TEntity, object>>[] identifierExpressions) 
where TEntity : class
{
Expression<Func<TEntity, bool>> allExpresions = null;

foreach (Expression<Func<TEntity, object>> identifierExpression in identifierExpressions)
{
Func<TEntity, object> vv = identifierExpression.Compile();
object constant = vv(entity);

ConstantExpression constExp = Expression.Constant(constant, typeof(object));
BinaryExpression equalExpression1 = Expression.Equal(identifierExpression.Body, constExp);
Expression<Func<TEntity, bool>> equalExpression2 = Expression.Lambda<Func<TEntity, bool>>(equalExpression1, identifierExpression.Parameters);

if (allExpresions == null)
{
allExpresions = equalExpression2;
}
else
{
var visitor = new ExpressionSubstitute(allExpresions.Parameters[0], identifierExpression.Parameters[0]);
var modifiedAll = (Expression<Func<TEntity,bool>>)visitor.Visit(allExpresions);
BinaryExpression bin = Expression.And(modifiedAll.Body, equalExpression2.Body);
allExpresions = Expression.Lambda<Func<TEntity, bool>>(bin, identifierExpression.Parameters);
}
}

TEntity existingEntity = null;
if (allExpresions != null)
{
existingEntity = context.Set<TEntity>().FirstOrDefault(allExpresions);
}

if (existingEntity == null)
{
context.Set<TEntity>().Add(entity);
}
else
{
entity = existingEntity;
}
}

关于c# - 组合多个表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33804942/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com