我目前正在使用NHibernate的C#项目中工作。在项目中,我们有一个名为“ Auftrag”的表,其中我只需要一些列。
仅选择我需要的列,我使用此代码:
ProjectionList projectionListSubTypeAuftrag = Projections.ProjectionList();
projectionListSubTypeAuftrag
.Add(Projections.Property("AuftragID"), "Id")
.Add(Projections.Property("Status"), "Status")
.Add(Projections.Property("Typ"), "Typ");
DetachedCriteria auftragCriteria = DetachedCriteria.For(typeof(Auftrag));
auftragCriteria.SetProjection(projectionListSubTypeAuftrag);
auftragCriteria.SetResultTransformer(Transformers.AliasToBean(typeof(SubTypeAuftrag)));
IList<SubTypeAuftrag> auftragSubview;
using (ITransaction tx = session.BeginTransaction())
{
auftragSubview = auftragCriteria.GetExecutableCriteria(session).List<SubTypeAuftrag>();
tx.Commit();
}
这可以正常工作,并返回表中的所有行。现在,我要过滤条件:Status != 'A'
。
我试图通过以下代码实现这一点
auftragCriteria.Add(Restrictions.Not(Restrictions.Eq("Status", 'A')));
如果现在运行代码,我会收到异常:
System.Data.SqlClient.SqlException:创建或更改表“ FakeWorkTable”失败,因为最小行大小为16017,包括4个字节的内部开销。这超过了最大值允许的表行大小为8094字节。
当我查看生成的SQL语句时,一切看起来都很正常,我也可以在Microsoft SSMS中运行它。
现在我不了解的部分是,当我将auftragCriteria.Add(Restrictions.Not(Restrictions.Eq("Status", 'A')));
更改为auftragCriteria.Add(Restrictions.Eq("Status", 'A'));
时,一切正常。
我想念什么?
我找到了解决方法:
auftragCriteria.Add(Expression.Sql("Status <> 'A'"));
作品。
如果使用auftragCriteria.Add(Restrictions.Not(Restrictions.Eq("Status", 'A')));
,则会得到此SQL查询
SELECT this_.auftragid as y0_,
this_.status as y1_,
this_.typ as y2_
FROM auftrag this_
WHERE not (this_.status = 'A' /* @p0 */)
如果我使用auftragCriteria.Add(Expression.Sql("Status <> 'A'"));
,我会得到这个:
SELECT this_.auftragid as y0_,
this_.status as y1_,
this_.typ as y2_
FROM auftrag this_
WHERE Status <> 'A'
他们的行为不一样吗?
据我从查看NHibernate源代码可以看出的,使用Restrictions.Not(Restrictions.Eq("Status", 'A'))
似乎是实现“不等于”运算符的正确方法。在Java版本的Hibernate中,有Restrictions.ne
被转换为'<>'运算符。
我要检查的几件事。使用最新的NHibernate版本运行代码,然后查看问题是否仍然存在。从错误消息来看,我怀疑您在此处显示的代码中还有更多的事情发生。尝试用可能的最少代码来复制问题。
[我认为比使用Expression.Sql
更好的另一种解决方法是将Lt
和Gt
与Or
一起使用:
auftragCriteria.Add(
Restrictions.Or(
Restrictions.Lt("Status", 'A'),
Restrictions.Gt("Status", 'A')));
应该成为:
WHERE (this_.status < 'A' or this.status > 'A')