如何构建这个复杂的表达式Func? [英] How to build this complex Expression Func?

查看:163
本文介绍了如何构建这个复杂的表达式Func?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用一个 EF 网站,我有这个数据库对象:

  public partial class Association 
{
public Association()
{
this.Users = new HashSet< User>();
}

public Guid Id {get;组; }
public Guid ItemId {get;组; }

[ForeignKey(ItemId)]
public virtual Item Item {get;组; }

[InverseProperty(Association)]
public virtual ICollection< User>用户{get;组;
}

项目类:

  public partial class Item 
{
public Item()
{
this.Associations = new HashSet< Association>() ;
}

public Guid Id {get;组; }
public ItemTypeEnum Type {get;组; }

[InverseProperty(Item)]
public virtual ICollection< Association>协会{get;组; }
}

此字典:

  public static Dictionary< ItemTypeEnum,int> MaxOccupationRange = new Dictionary< ItemTypeEnum,int>()
{
{ItemTypeEnum.Type1,1},
{ItemTypeEnum.Type2,2},
{ItemTypeEnum.Type3,5 },
{ItemTypeEnum.Type4,10},
};

我需要一个 Expression&FunC< Association,bool>> / code>将返回 true if association.Users.Count< MaxOccupationRange [association.Item.Type] ,否则 false

我认为这应该大致如下但不幸的是,我对于表达式的概念不够熟悉,可以实现这种做法。



调试时以下结果,似乎它计算(一个未优化但是)正确的表达式。

  public static Expression< Func< TSource,布尔>> MyExprMethod< TSource,TKey,TKey2,TValue>(表达<功能>源,TKey>源,表达< Func< TSource,TKey2>> source2,IReadOnlyDictionary< TKey,TValue> dict)
{
var body = dict
.Aggregate((Expression)null,(next,dicEntry)=> next == null
?Expression.Condition

Expression.LessThan (source2.Body,Expression.Constant(dicEntry.Value)),
Expression.Constant(true),
Expression.Constant(false)

:Expression.Condition

Expression.Equal(source.Body,Expression.Constant(dicEntry.Key)),
Expression.Condition

Expression.LessThan(source2.Body, Expression.Constant(dicEntry.Value)),
Expression.Constant(true),
next
),
next

);

return Expression.Lambda }

我尝试这样调用:

  var expr = MyHelper.MyExprMethod((Association x)=> x.Item.Type,(Association b)=> b.Users.Count,Item .MaxOccupationRange); 

但显然,它抱怨 b 参数由于它没有出现在结果lambda中,因此不被分配。

我尝试了许多东西(匿名类型而不是两个来源等),但是似乎我对这个概念太陌生了,我不能找到一种方式来产生这样一个表达方式。



有没有人可以给我看?



非常感谢。 / p>

编辑



这是呼叫上下文: / p>

  var filter = PredicateUtils.True< Association>(); 

var expr = MyHelper.MyExprMethod((Association x)=> x.Item.Type,(Association b)=> b.Users.Count,Item.MaxOccupationRange);
filter = filter.And(expr);

var associations = entities.Associations.Where(filter);
返回关联.OrderBy(a => a.Id).ToPagedList(pageNb,2);

这里是最后一行显示的消息(ToPagedList):参数'b'未绑定到指定的LINQ to Entities查询表达式

解决方案

我想你需要重新参数化第二个表达式

  public static Expression< Func< TSource,bool>> MyExprMethod< TSource,TKey,TKey2,TValue>(表达<功能>源,TKey>源,表达< Func< TSource,TKey2>> source2,IReadOnlyDictionary< TKey,TValue> dict)
{
source2 = PredicateRewriter.Rewrite(source2,source.Parameters [0]);
var body = dict

通过助手

  public class PredicateRewriter 
{
public static Expression< Func< T,U>>重写< T,U>(表达式< Func< T,U> exp,// string newParamName
ParameterExpression param)
{
// var param = Expression.Parameter参数[0] .Type,newParamName);
var newExpression = new PredicateRewriterVisitor(param).Visit(exp);

return(Expression< Func< T,U>)newExpression;
}

与访客模式



私人类PredicateRewriterVisitor:ExpressionVisitor
{
private readonly ParameterExpression _parameterExpression;

 

public PredicateRewriterVisitor(ParameterExpression parameterExpression)
{
_parameterExpression = parameterExpression;
}

protected override表达式访问参数(ParameterExpression node)
{
return _parameterExpression;
}
}
}


I'm currently working on an EF website where I have this database object:

public partial class Association
{
    public Association()
    {
        this.Users = new HashSet<User>();
    }

    public Guid Id { get; set; }
    public Guid ItemId { get; set; }

    [ForeignKey("ItemId")]
    public virtual Item Item { get; set; }

    [InverseProperty("Association")]
    public virtual ICollection<User> Users { get; set; }
}

An Item class:

public partial class Item
{
    public Item()
    {
        this.Associations = new HashSet<Association>();
    }

    public Guid Id { get; set; }
    public ItemTypeEnum Type { get; set; }

    [InverseProperty("Item")]
    public virtual ICollection<Association> Associations { get; set; }
}

And this dictionary:

public static Dictionary<ItemTypeEnum, int> MaxOccupationRange = new Dictionary<ItemTypeEnum, int>()
    {
        { ItemTypeEnum.Type1, 1 },
        { ItemTypeEnum.Type2, 2 },
        { ItemTypeEnum.Type3, 5 },
        { ItemTypeEnum.Type4, 10 },
    };

I would need an Expression<Func<Association, bool>> that would return true if association.Users.Count < MaxOccupationRange[association.Item.Type], and else false.
I think this should roughly look like the following method but unfortunately, I'm not familiar enough with the Expression concept to achieve this kind of thing.

When debugging the following result, it seems like it computes (an not optimized but) correct expression.

public static Expression<Func<TSource, bool>> MyExprMethod<TSource, TKey, TKey2, TValue>(Expression<Func<TSource, TKey>> source, Expression<Func<TSource, TKey2>> source2, IReadOnlyDictionary<TKey, TValue> dict)
    {
        var body = dict
            .Aggregate((Expression)null, (next, dicEntry) => next == null
                ? Expression.Condition
                    (
                        Expression.LessThan(source2.Body, Expression.Constant(dicEntry.Value)),
                        Expression.Constant(true),
                        Expression.Constant(false)
                    )
                : Expression.Condition
                    (
                        Expression.Equal(source.Body, Expression.Constant(dicEntry.Key)),
                        Expression.Condition
                        (
                            Expression.LessThan(source2.Body, Expression.Constant(dicEntry.Value)),
                            Expression.Constant(true),
                            next
                        ),
                        next
                    )
                );

        return Expression.Lambda<Func<TSource, bool>>(body, source.Parameters[0]);
    }

I try to call it this way:

var expr = MyHelper.MyExprMethod((Association x) => x.Item.Type, (Association b) => b.Users.Count, Item.MaxOccupationRange);

But obviously it complains about the b parameter to be unassigned since it does not appear in the result lambda.
I tried many things (anonymous type instead of two sources etc.) but it seems that I'm too unfamiliar with the concept, I could not find a way to generate such an expression.

Would anybody please show me ?

Thanks a lot.

EDIT

Here's the call context:

var filter = PredicateUtils.True<Association>();

var expr = MyHelper.MyExprMethod((Association x) => x.Item.Type, (Association b) => b.Users.Count, Item.MaxOccupationRange);
filter = filter.And(expr);

var associations = entities.Associations.Where(filter);
return associations .OrderBy(a => a.Id).ToPagedList(pageNb, 2);

And here's the message, shown on the last line (ToPagedList): The parameter 'b' was not bound in the specified LINQ to Entities query expression

解决方案

I guess you need to re-parametrize the second expression

    public static Expression<Func<TSource, bool>> MyExprMethod<TSource, TKey, TKey2, TValue>(Expression<Func<TSource, TKey>> source, Expression<Func<TSource, TKey2>> source2, IReadOnlyDictionary<TKey, TValue> dict)
    {
        source2 = PredicateRewriter.Rewrite(source2, source.Parameters[0]);
        var body = dict

through a helper

    public class PredicateRewriter
    {
        public static Expression<Func<T, U>> Rewrite<T,U>(Expression<Func<T, U>> exp, //string newParamName
            ParameterExpression param)
        {
            //var param = Expression.Parameter(exp.Parameters[0].Type, newParamName);
            var newExpression = new PredicateRewriterVisitor(param).Visit(exp);

            return (Expression<Func<T, U>>)newExpression;
        }

with a Visitor pattern

        private class PredicateRewriterVisitor : ExpressionVisitor
        {
            private readonly ParameterExpression _parameterExpression;

            public PredicateRewriterVisitor(ParameterExpression parameterExpression)
            {
                _parameterExpression = parameterExpression;
            }

            protected override Expression VisitParameter(ParameterExpression node)
            {
                return _parameterExpression;
            }
        }
    }

这篇关于如何构建这个复杂的表达式Func?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆