【问题标题】:How to combine 2 c# Expression of different type in Devforce?如何在 Devforce 中组合 2 个不同类型的 c# 表达式?
【发布时间】:2023-04-02 14:15:01
【问题描述】:

我写了一些谓词,希望它们构造一个实体查询。

通常如果我有一个EntityA 类型的实体,我会写这种表达式Expression<Func<EntityA, bool>>

我想要完成的是在 EntityA 类型的查询中使用 Expression<Func<EntityB, bool>>

假设EntityA 有一个EntityB 的集合。我对EntityA 有一个谓词,例如:

public static Expression<Func<EntityA, bool>> HasId(int id)
{
    return p => p.Id == id;
}

现在在查询我的 EntityB 时,我希望能够使用这个谓词以避免在 Expression&lt;EntityB, bool&gt;&gt; (with p =&gt; p.EntityA.Id == id) 中重写它。

我想要类似的东西:

Expression<Func<EntityB, bool>> predicates = p => **initial condition on EntityB**
var myfunc = HasId(12).Compile();
predicates = predicates.And(p => myfunc(p.EntityA));

这种语法不起作用。

如何在Expression&lt;Func&lt;EntityB,bool&gt;&gt; 谓词中使用Expression&lt;Func&lt;EntityA, bool&gt;&gt;

* 编辑 *

忘了提及我在我的项目中使用的是 Devforce(来自 Ideablade)。 谓词。And 来自它们(我最初以为我来自系统)。

错误信息是:

未知表达式类型:Invoke(value(UserQuery+c__DisplayClass1).myfunc , p.EntityA)

堆栈跟踪是:

   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressionCore(Expression e)
   à IdeaBlade.Linq.TransformExpressionVisitor.VisitExpressionCore(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpression(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressionCore(Expression e)
   à IdeaBlade.Linq.TransformExpressionVisitor.VisitExpressionCore(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpression(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressionCore(Expression e)
   à IdeaBlade.Linq.TransformExpressionVisitor.VisitExpressionCore(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpression(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressionCore(Expression e)
   à IdeaBlade.Linq.TransformExpressionVisitor.VisitExpressionCore(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpression(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressionCore(Expression e)
   à IdeaBlade.Linq.TransformExpressionVisitor.VisitExpressionCore(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpression(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.<VisitExpressions>b__0(Expression e)
   à System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   à System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   à System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressions(IEnumerable`1 expressions)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpressionCore(Expression e)
   à IdeaBlade.Linq.TransformExpressionVisitor.VisitExpressionCore(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.VisitExpression(Expression expr)
   à IdeaBlade.Linq.ExpressionVisitor.Visit(Expression expr)
   à IdeaBlade.EntityModel.EntityQuery`1.ProcessExpression(Expression e)
   à IdeaBlade.EntityModel.EntityQuery`1..ctor(Expression expression, IQueryable queryable)
   à IdeaBlade.EntityModel.EntityQuery`1.System.Linq.IQueryProvider.CreateQuery[TElement](Expression expression)
   à System.Linq.Queryable.Where[TSource](IQueryable`1 source, Expression`1 predicate)
   à IdeaBlade.EntityModel.EntityQueryExtensions.Where[TSource](IEntityQuery`1 source1, Expression`1 predicate)

【问题讨论】:

  • 您说“此语法不起作用”,但您遇到了什么错误?
  • 他可能正在使用 LinqKit - 其中包括表达式的扩展方法。
  • 我注意到你做了predicates.And(...)。你想在那里做什么?请注意,有一个 static 方法 Expression.And(Expression, Expression) (MSDN)。但是,它的语法需要 两个 表达式参数(@Mike,或者他可能正在使用 LinqKit...)
  • 已编辑,实际上我使用的是 Ideablade 的 Devforce。助手“And”是由他们提供的,尽管它在 c# 库中很常见。我想要实现的是组合多个 Expression> 而一些针对查询的主要实体,而另一些则针对一些导航属性
  • DevForce 不支持 Invoke,因为它在将表达式树序列化到服务器时无法序列化函数调用。尽管您可能无法使用现有的谓词,但 DevForce 中的其他一些动态查询功能可能仍然有帮助 - 请查看 PredicateBuilder 和 PredicateDescription here

标签: c# lambda expression-trees devforce


【解决方案1】:

您可以动态构建Expression&lt;EntityB,bool&gt; 谓词,但它的可重用性值得怀疑。请注意,如果使用实体框架,则不支持调用表达式。

--更新

这可行且可重复使用:

public static Expression<Func<T2, bool>> SubPredicate<T1, T2>( Expression<Func<T1, bool>> predicate, Expression<Func<T2, T1>> selector )
{
    var parms = selector.Parameters;

    var a = Expression.Invoke( selector, parms );

    var invocation = Expression.Invoke( predicate, a );

    return ( Expression<Func<T2, bool>> )Expression.Lambda( invocation, parms );
}

用法:

var filteredResults = list.Where( 
    SubPredicate<EntityA, EntityB>( 
        a => a.ID % 2 == 1, 
        b => b.EntityA )
        .Compile() );

-- 演示:

static void Main( string[] args )
{
    var list = new List<EntityB>()
    {
        new EntityB()
        {
            ID = 11,
            EntityA = new EntityA() { ID = 1 }
        },
        new EntityB()
        {
            ID = 22,
            EntityA = new EntityA() { ID = 2 }
        },
        new EntityB()
        {
            ID = 33,
            EntityA = new EntityA() { ID = 3 }
        },
    };

    var filteredResults = list.Where( 
        SubPredicate<EntityA, EntityB>( 
            a => a.ID % 2 == 1, 
            b => b.EntityA )
            .Compile() );

    foreach( var b in filteredResults )
    {
        Console.WriteLine( "{0}/{1}", b.ID, b.EntityA.ID );
    }

    Console.ReadLine();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    相关资源
    最近更新 更多