2013-09-21 58 views
3

我的问题LINQ表达与此一:linq-expression-with-generic-class-properties与一般财产

这一次,我想获得具有共同的ID新创建的对象。 id实际上是外键,因此可以有不同的名称。

我想出了以下内容:

public static IEnumerable<T> GetNew<TId, T>(IQueryable<T> objects, TId id, DateTime date, Expression<Func<T, TId>> idSelector) 
    where T : class, ISyncable<TId> 
{ 
    return objects.Where(o => idSelector(o) == id && o.CreatedDate > date); 
} 

的方法将被称为像这样:

var modified = GetNew(dbObjects, id, date, entity => entity.PersonId); 

不幸的是我得到的错误:

'idSelector' is a variable but is used like a method. 

传递到表达式该方法应该这样做:

objects.Where(o => o.PersonId == id && o.CreatedDate > date); 

回答

7

你需要建立一个新的表达代表的条件,并传递到Where

public static IEnumerable<T> GetNew<TId, T>(IQueryable<T> objects, TId id, DateTime date, Expression<Func<T, TId>> idSelector) 
    where T : class, ISyncable<TId> 
{ 
    var paramExpr = Expression.Parameter(typeof(T)); 
    var idEqExpr = Expression.Equal(Expression.Invoke(idSelector, paramExpr), Expression.Constant(id)); 
    var createdPropExpr = Expression.Property(paramExpr, "CreatedDate"); 
    var gtExpr = Expression.GreaterThan(createdPropExpr, Expression.Constant(date)); 
    var andExpr = Expression.And(idEqExpr, gtExpr); 

    var condExpr = Expression.Lambda<Func<T, bool>>(andExpr, paramExpr); 

    return objects.Where(condExpr); 
} 

编辑:如果你知道idSelector是一个属性的表达,你可以提取所引用的属性,并创建一个新属性表达式代替使用Invoke

var idProperty = (PropertyInfo)((MemberExpression)idSelector.Body).Member; 
var idEqExpr = Expression.Equal(Expression.Property(paramExpr, idProperty), Expression.Constant(id)); 
+1

或者调用'Where'方法两次。 – MarcinJuraszek

+0

不幸的是我得到了这个异常:LINQ to Entities不支持LINQ表达式节点类型'Invoke'。有没有办法阻止这种情况发生? – niklr

+1

@Moo - 如果你期望'idSelector'是一个属性表达式,你可以用它来代替'Invoke'。如果你不能这样做,你必须尝试递归地解构它,并构建一个不使用'Invoke'的新表达式。查看更新。 – Lee