我已经为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转换”。
有没有办法解决这个问题?
答案 0 :(得分: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理解我们的 intent ,并创建合适的TSQL实现同样的目标。
答案 1 :(得分:2)
您可以尝试以下操作:
activeUsers = users.AsEnumerable().Where(u => u.IsActive);
请注意,标准IsActive将不会转换为SQL,因为从数据库角度来看,不了解IsActive背后的逻辑。因此,数据库将对整个表用户执行读取,并且标准将应用于内存中。
答案 2 :(得分: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);