自定义属性和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转换"。
有办法解决这个问题吗?
您显示的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);