2

我已向 LINQ-to-SQL 实体添加了一个自定义属性:

public partial class User
{
    public bool IsActive
    {
        get
        {
            // note that startDate and endDate are columns of User table
            return startDate <= DateTime.Now && endDate >= DateTime.Now;
        }
    }
}

现在我需要将此属性与 lambda 表达式一起使用:

activeUsers = users.Where(u => u.IsActive);

但是当执行此代码时,我得到一个System.NotSupportedException. 异常消息显示“不支持成员 'User.IsActive' 的 SQL 转换”

有没有办法解决这个问题?

4

3 回答 3

6

您展示的IsActive是常规 C# - 它将被编译为 IL,并且不可用于 LINQ-to-SQL(等)检查并转换为 TSQL 以在数据库中执行。这里的一种选择可能是:

public static Expression<Func<User,bool>> GetIsActiveFilter() {
    return user => user.StartDate <= DateTime.Now &&
                   user.EndDate >= DateTime.Now;
}

那么你应该可以使用:

activeUsers = users.Where(User.GetIsActiveFilter());

或类似地-也许是扩展方法:

public static IQueryable<User> ActiveOnly(this IQueryable<User> users) {
    return users.Where(user => user.StartDate <= DateTime.Now &&
                               user.EndDate >= DateTime.Now);
}

然后:

activeUsers = users.ActiveOnly();

这里的不同之处在于我们始终使用IQueryable<T>接口和表达式树,这使得 LINQ 能够理解我们的意图,并创建合适的 TSQL 来实现相同的目的。

于 2013-02-06T10:25:21.280 回答
2

您可以尝试以下方法:

activeUsers = users.AsEnumerable().Where(u => u.IsActive);

请注意,条件 IsActive 不会被转换为 SQL,因为 IsActive 背后的逻辑从数据库的角度来看是未知的。因此数据库将对整个表用户执行读取,并且标准将在内存中应用。

于 2013-02-06T10:07:45.307 回答
1

我以这种方式解决了我的类似问题:

我的 ORM 是 NHibernate,底层数据库是 Oracle,当我需要添加一些像 IsActive 这样的字段时,做了这样的事情

public partial class User
{
   public bool IsActive{get;set;}
}

在相关的映射文件中添加类似这样的内容

<property name="IsActive" access="property" insert="false" update="false"
  formula="case when startDate  <= sysdate And endDate  >= sysdate then 1 else 0 end" />

现在你可以使用

activeUsers = users.Where(u => u.IsActive);
于 2013-02-06T10:56:15.697 回答