は私が組み合わせる複数の式の木
パラメーター「P」はエンティティへのLINQ指定 クエリ式にバインドされていなかった次のエラーを取得しています。
私は問題を理解(の同じインスタンスは、ツリー内のすべての式で使用されなければならない)と私は、オンラインではなく運で見つけたソリューションを使用しようとしました。
これは、プロパティの数に基づいて、エンティティの検索のための表現を生成し、私の方法
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
それは私には、以下を実行に似た何かを生成します。
することができますConstantExpression
とe.Name & & e.Ageの交換
context.Set<TEntity>().FirstOrDefault(p=>p.Name == e.Name && p.Age == e.Age);
上の方法を参照してください私はすべてのユニークなパラメータをつかみ、parameters
にそれらを格納するpの場合は、同じ変数を使用します。これは最初ですが、params
配列として渡されたExpression<Func<TEntity, bool>>
のそれぞれのパラメータのインスタンスを置き換える必要があります。これが失敗します。
を渡す.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;
}
}
すぐに考えてみましょう。2番目のパラメータに別の文字を使用してみましたか? (すなわち、p => p.Name、f => f.Age) –
入力のおかげで、これは決してうまくいかないでしょう。それはラムダ –
のために供給されるパラメータの不正確な数を投げますクエリーを組み合わせるのではなく、それらを連続して適用してみませんか? 'results =/*フルセット* /; foreach(式){結果= results.Where(式)} '? EFは 'IQueryable'を使用するので、フレームワークは必要になるまで実行を延期し、すべての述語をSQL用の単一の問合せに結合します。 – Basic