对于where子句通用表述 - “的LINQ表达式节点类型‘调用’在LINQ不支持到实体”。(Gen

2019-08-01 04:36发布

我想写一个非常通用的方式来加载分批EF实体,使用包含方法生成语句SQL。 我找到了工作,如果我通过在整个表达式,但是当我尝试动态构建表达式,我得到一个“的LINQ表达式节点类型‘调用’不支持LINQ到实体。” 所以我知道这意味着EF认为我打电话任意方法,它不能把它翻译成SQL,但我无法弄清楚如何得到它了解底层的表达。

所以,如果我做这样的事情(只显示相关的片段):

函数声明:

public static List<T> Load<T>(IQueryable<T> entityQuery, int[] entityIds, Func<T, int> entityKey, int batchSize = 500, Func<T, bool> postFilter = null) where T : EntityObject
{
    var retList = new List<T>();

    // Append a where clause to the query passed in, that will use a Contains expression, which generates a SQL IN statement.  So our SQL looks something like
    // WHERE [ItemTypeId] IN (1921,1920,1922)
    // See http://rogeralsing.com/2009/05/21/entity-framework-4-where-entity-id-in-array/ for details
    Func<int[], Expression<Func<T, bool>>> containsExpression = (entityArray => (expr => entityArray.Contains(entityKey(expr))));

    // Build a new query with the current batch of IDs to retrieve and add it to the list we are returning
    newQuery = entityQuery.Where<T>(containsExpression(entityIds));
    retList.AddRange(newQuery.ToList());

    return retList;
} 

通话功能:

var entities = BatchEntity.Load<ItemType>(from eItemType in dal.Context.InstanceContainer.ItemTypes
select eItemType
, itemTypeData
, (ek => ek.ItemTypeId)
);

我得到“的LINQ表达式节点类型‘调用’不支持LINQ到实体。”

但是,如果我改变它是这样的:

函数声明:

public static List<T> Load<T>(IQueryable<T> entityQuery, int[] entityIds, Func<int[], Expression<Func<T, bool>>> containsExpression, int batchSize = 500, Func<T, bool> postFilter = null) where T : EntityObject
{
    var retList = new List<T>();

    // Build a new query with the current batch of IDs to retrieve and add it to the list we are returning
    newQuery = entityQuery.Where<T>(containsExpression(entityIds));
    retList.AddRange(newQuery.ToList());

    return retList;
} 

通话功能:

var entities = BatchEntity.Load<ItemType>(from eItemType in dal.Context.InstanceContainer.ItemTypes
select eItemType
, itemTypeData
, (entityArray => (ek => entityArray.Contains(ek.ItemTypeId)))
);

它工作正常。 有没有什么办法可以让EF理解更宽泛的版本?

Answer 1:

的问题,因为你描述是,在第一个例子中的EntityKey功能是不透明的,因为它的类型是Func键,而不是表达。 但是,你可以得到你想要通过实施撰写()方法来两个表达式相结合的行为。 我张贴的代码来实现构成这样一个问题: 使用Expression <Func键<T,X >> Linq中含有扩展 。

随着撰写()来实现,你的函数可以实现如下:

public static List<T> Load<T>(this IQueryable<T> entityQuery, 
                              int[] entityIds, 
                              // note that this is an expression now
                              Expression<Func<T, int>> entityKey, 
                              int batchSize = 500, 
                              Expression<Func<T, bool>> postFilter = null) 
    where T : EntityObject
{
    Expression<Func<int, bool>> containsExpression = id => entityIds.Contains(id);
    Expression<Func<T, bool>> whereInEntityIdsExpression = containsExpression.Compose(entityKey);

    IQueryable<T> filteredById = entityQuery.Where(whereInEntityIdsExpression);

    // if your post filter is compilable to SQL, you might as well do the filtering
    // in the database
    if (postFilter != null) { filteredById = filteredById.Where(postFilter); }

    // finally, pull into memory
    return filteredById.ToList();
} 


文章来源: Generic expression for where clause - “The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.”