自定义属性和lambda表达式

本文关键字:表达式 lambda 自定义属性 | 更新日期: 2023-09-27 17:58:01

我为LINQ到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);

但是当执行这个代码时,我得到一个CCD_。异常消息表示"不支持成员'User.IsActive'的SQL转换"

有办法解决这个问题吗?

自定义属性和lambda表达式

您显示的IsActive是常规C#-它将被编译到IL,LINQ到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来实现这一点。

您可以尝试以下操作:

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

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

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

我的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);