如何在 Entity Framework 查询之间共享对象级逻辑?

How can I share object level logic across Entity Framework queries?

我希望在 Entity Framework 中跨多个查询共享一些非常简单的逻辑。假设我有以下型号

public class User
{
    // user properties
    public ICollection<UserRole> Roles { get; set; }
}

public class UserRole : IDateRestricted
{
    public RoleType Type { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

public interface IDateRestricted
{
    DateTime StartDate { get; set; }
    DateTime? EndDate { get; set; }
}

如果我使用的是普通的 LINQ,我可以创建一个简单的扩展方法来确定该角色当前是否处于活动状态。

public static class DateRestrictedExtensions
{
    public static Boolean IsActive(this IDateRestricted entity)
    {
        return entity.StartDate <= DateTime.Now && (entity.EndDate == null || entity.EndDate > DateTime.Now);
    }
}

我可以像这样使用它。

var admins = users.Where(x => x.Roles.Any(role => role.Type == RoleType.Admin && role.IsActive()));

使用 entity framework 这会失败,可怕的是:

LINQ to Entities does not recognize the method Boolean IsActive(Domain.Interfaces.IDateRestricted) method, and this method cannot be translated into a store expression.

有没有一种方法可以共享此逻辑并让 LINQ to Entities 在查询时支持它?

您应该使用 Expression<Func<IDateRestricted, bool>> 而不是 Func<IDateRestricted, bool> - 出现的异常描述恰好指向它:

public static class DateRestrictedExtensions
{
    public static Expression<Func<IDateRestricted, bool>> IsActive()
    {
        return entity => entity.StartDate <= DateTime.Now 
                         && (entity.EndDate == null || entity.EndDate > DateTime.Now);
    }
}

var admins = users.Where(x => x.Roles.AsQueryable().Where(role.Type == RoleType.Admin)
                                   .Any(DateRestrictedExtensions.IsActive()));