NHibernate中DetachedCriteria结合外部变量实现OR条件的问题
解决NHibernate DetachedCriteria实现动态OR查询条件的问题
先明确你要实现的SQL核心逻辑:
DECLARE @subtype varchar() SET @subtype=null SELECT E.* FROM ErrorCRM WHERE TypeError='A' AND (SubtypeError=@subtype OR @subtype is null)
这段SQL的关键是当外部变量@subtype为null时,不对SubtypeError做过滤;当@subtype有值时,只匹配SubtypeError等于该值的记录。
你当前的DetachedCriteria代码存在逻辑偏差:你写的Expression.Eq(SubTipoError,null)是判断实体的SubTipoError是否为null,而原SQL是判断外部传入的变量是否为null,这完全搞反了判断对象。
方案一:最简洁的动态条件写法
既然当外部变量SubTipoError为null时,SQL里的(SubtypeError=@subtype OR @subtype is null)等价于恒成立,我们可以直接根据变量是否为空来动态添加条件,逻辑更清晰:
// 初始化查询 DetachedCriteria query = DetachedCriteria.For<ErrorCRM>("e") .Add(Restrictions.Eq("TipoError", TipoError)) .Add(Restrictions.Eq("Sentido", Sentido)); // 根据外部变量动态添加SubTipoError过滤条件 if (SubTipoError != null) { query.Add(Restrictions.Eq("SubTipoError", SubTipoError)); }
方案二:严格对应原SQL的OR结构写法
如果需要完全贴合原SQL的OR逻辑结构,可以用Disjunction(OR组)结合SqlRestriction来实现:
DetachedCriteria query = DetachedCriteria.For<ErrorCRM>("e") .Add(Restrictions.Eq("TipoError", TipoError)) .Add(Restrictions.Eq("Sentido", Sentido)) .Add(Restrictions.Disjunction() // 对应SQL里的@subtype is null .Add(Restrictions.SqlRestriction("@subtype is null", new object[] { SubTipoError }, new IType[] { NHibernateUtil.String })) // 对应SQL里的SubtypeError = @subtype .Add(Restrictions.Eq("SubTipoError", SubTipoError)) );
方案三:Lambda表达式简化写法(NHibernate新版本支持)
如果你的NHibernate版本支持Lambda表达式,可以用更直观的语法:
var query = DetachedCriteria.For<ErrorCRM>() .Where(e => e.TipoError == TipoError && e.Sentido == Sentido) .Where(Restrictions.Disjunction() .Add<ErrorCRM>(_ => SubTipoError == null) .Add<ErrorCRM>(e => e.SubTipoError == SubTipoError) );
关键注意点
一定要区分实体属性和外部变量:构建条件时,判断的是外部传入的SubTipoError是否为null,而不是数据库实体的SubTipoError字段——这是你之前代码出错的核心原因。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

