实体框架通用谓词

时间:2014-01-06 09:18:20

标签: c# .net linq entity-framework

我需要共享4-5个差异实体集的谓词,最好不要复制代码。所有实体都实现了接口IEntity

private Expression<Func<T, bool>> GetUpdatedPredicate<T>(DateTime? lastUpdated) where T : IEntity {
    if (lastUpdated.HasValue) {
        return x => (
            x.CreatedAt >= lastUpdated ||
            (x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated)
        );
    }

    return x => true;
}

然后像这样使用多个实体集:

(
     from s in Db.EntityA.Where(GetUpdatedPredicate<EntityA>(lastUpdated))
     where (
         s.User.Id == 1
     )
     select s
 ).Future();

但是给出了错误: 无法将类型'EntityA'强制转换为'IEntity'。 LINQ to Entities仅支持转换EDM原语或枚举类型。有没有办法在不重复代码的情况下执行此操作?

3 个答案:

答案 0 :(得分:3)

实体框架在此处存在接口类型约束问题:

where T : IEntity

您需要添加一个T需要成为类的附加约束:

where T : class, IEntity

另外,如果您开始发现LINQ表达式,我强烈推荐LinqKit库。它有一些非常非常漂亮的东西。

答案 1 :(得分:0)

我提出了另一种方法。

首先,您将拥有一个私有静态方法,而不是使用返回表达式的方法:

private static bool Evaluate(IEntity x, DateTime? lastUpdated) {
    if (lastUpdated.HasValue) {
        return x.CreatedAt >= lastUpdated ||
            (x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated)
        );
    }

    return true;
}

显然你可以更好地提到这一点。然后使用它:

var result = Db.EntityA.Where(i => i.Evaluate(i, lastUpdated));

答案 2 :(得分:0)

EF现在尝试将对方法的调用包含在生成的表达式中,这将无效。您必须从表达式中排除方法调用。

在定义查询之前尝试从方法创建表达式(不,我还没有测试过)。

DateTime lastUpdated = ...;
var updatedPredicate = GetUpdatedPredicate<EntityA>(lastUpdated);
var query = 
(
     from s in Db.EntityA.Where(updatedPredicate)
     where (
         s.User.Id == 1
     )
     select s
 ).Future();