2017-02-04 60 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

這很好,謝謝你,你讓我的一天^^ –