2017-02-04 61 views
0

我目前工作的一个EF网站,我有这样的数据库对象:如何构建这个复杂的Expression Func?

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; } 
} 

项目类:

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; } 
} 

而该词典:

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>>如果association.Users.Count < MaxOccupationRange[association.Item.Type]将返回true,否则返回false
我认为这应该大致看起来像下面的方法,但不幸的是,我不熟悉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]); 
    } 

我尝试调用这种方式:

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

但很明显,它抱怨的b参数是未分配的,因为它不会在结果拉姆达出现。
我尝试了很多事情(匿名类型而不是两个来源等),但似乎我对这个概念太不熟悉,我找不到一种方法来生成这样的表达式。

有人请告诉我吗?

非常感谢。

编辑

这里的呼叫内容:

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); 

而这里的消息,在最后一行(ToPagedList)所示:The parameter 'b' was not bound in the specified LINQ to Entities query expression

+0

哪里不抱怨关于B?上面的代码编译并运行,*除*'EF'外。 – 2017-02-04 13:59:31

+0

感谢您的回答,我编辑了第一篇文章,希望这可以帮助 –

+0

您希望'协会x'和'协会b'成为* same *参数:看看我的答案,我正在展示如何做到这一点。 – 2017-02-04 15:34:06

回答

1

我猜你需要re-parametrize第二个表达式

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 

通过助手

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; 
     } 

与访客模式

 private class PredicateRewriterVisitor : ExpressionVisitor 
     { 
      private readonly ParameterExpression _parameterExpression; 

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

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

这很好,谢谢你,你让我的一天^^ –