【问题标题】:NHibernate JoinAlias query with null test not working带有空测试的 NHibernate JoinAlias 查询不起作用
【发布时间】:2012-12-02 18:39:30
【问题描述】:

NHibernate 中的 JoinAlias QueryOver 出现一些意外行为。

我的实体基本上是这样的:

public class Field
{
    public virtual long Id { get; protected set; }
    public virtual Field Parent { get; protected set; }
    public virtual FieldType Type { get; protected set; }
    public virtual string Value { get; protected set; }

...(Ctors etc
}

我的映射是这样的:

public class FieldMap : ClassMap<Field>
{
    public FieldMap()
    {
        Id(x => x.Id)
            .GeneratedBy.Native();

        References(x => x.Type)
            .Column("FieldTypeId")
            .LazyLoad()
            .Cascade.All()
            ;

        Map(x => x.Value);

        References(x => x.Parent)
            .Column("ParentFieldId")
            .Nullable()
            .LazyLoad()
            .Cascade.All()
            ;
    }

我的查询:

        Field fieldAlias = null;
        string typeAlias = null;
        Field parentFieldAlias = null;

        var query = getSession().QueryOver<Field>(() => fieldAlias)
            .JoinAlias(() => fieldAlias.Type, () => typeAlias)
            .Where(() => typeAlias.Name == type)
            .JoinAlias(() => fieldAlias.Parent, () => parentFieldAlias)
            .Where(() => (parentFieldAlias.Value == parentValue) || (parentFieldAlias == null))
            ;

就我而言,这应该给我一些这样的 SQL:

... WHERE (a.ParentFieldId == NULL) OR (a.ParentFieldId = c.FieldId AND c.Value = parentValue)

但我得到一个空引用异常。 (我假设当别名被解析并且 Parent 为空时)。

异常详情如下:

System.NullReferenceException occurred
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=NHibernate
  StackTrace:
       at NHibernate.Criterion.ConstantProjection..ctor(Object value)
       at NHibernate.Criterion.Projections.Constant(Object obj)
       at NHibernate.Impl.ExpressionProcessor.FindMemberProjection(Expression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessSimpleExpression(Expression left, Expression right, ExpressionType nodeType)
       at NHibernate.Impl.ExpressionProcessor.ProcessSimpleExpression(BinaryExpression be)
       at NHibernate.Impl.ExpressionProcessor.ProcessBinaryExpression(BinaryExpression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessExpression(Expression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessOrExpression(BinaryExpression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessBinaryExpression(BinaryExpression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessExpression(Expression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessLambdaExpression(LambdaExpression expression)
       at NHibernate.Impl.ExpressionProcessor.ProcessExpression(Expression`1 expression)
       at NHibernate.Criterion.QueryOver`2.Add(Expression`1 expression)
       at NHibernate.Criterion.QueryOver`2.Where(Expression`1 expression)
       at NHibernate.Criterion.QueryOver`2.NHibernate.IQueryOver<TRoot,TSubType>.Where(Expression`1 expression)
       at Ismoos.Director.FieldOptionsQuery.Execute(Service service, String type, String parentValue) in D:\Work\Ismoos\Ismoos\Director\Ismoos.Director\FieldOptionsQuery.cs:line 31
  InnerException:

我尝试了几种不同的方法,包括:

            .JoinAlias(() => fieldAlias.Parent, () => parentFieldAlias)
            .Where(Restrictions.Or(Restrictions.On(() => fieldAlias.Parent).IsNotNull,
                Restrictions.On(() => parentFieldAlias.Value).IsLike(parentValue))))

但这些都不起作用。

我有一个解决方法,在查询中省略对父字段值的限制,并在 QueryOver 返回后执行 LINQ 查询,如下所示:

        Field fieldAlias = null;
        string typeAlias = null;
        Field parentFieldAlias = null;

        var query = getSession().QueryOver<Field>(() => fieldAlias)
            .JoinAlias(() => fieldAlias.Type, () => typeAlias)
            .Where(() => typeAlias.Name == type)
            ;

        var list = query
        .List<Field>()
        ;

        return list
            .Where(x => (x.Parent == null) || (x.Parent.Value == parentValue))
            .ToList();

但这并不像在 QueryOver 中那样优化。

有什么建议吗?

【问题讨论】:

    标签: c# nhibernate nullreferenceexception queryover


    【解决方案1】:

    有限制的第二个解决方案可以完成这项工作。有两个问题。我们需要 LEFT JOIN 到 Parent 并且我看到 typo: IsNotNull 应该是 IsNull 以正确评估 OR 语句:

    损坏的解决方案IsNotNull(很可能是内部连接)

    .JoinAlias(() => fieldAlias.Parent, () => parentFieldAlias)
    .Where
    (
      Restrictions.Or(
        Restrictions.On(() => fieldAlias.Parent).IsNotNull, // here
        Restrictions.On(() => parentFieldAlias.Value).IsLike(parentValue)))
    )
    

    使用ORIsNull 并左连接:

    .JoinAlias(() => fieldAlias.Parent, () => parentFieldAlias
               , NHibernate.SqlCommand.JoinType.LeftOuterJoin)) // left join for NULL
    .Where
    (
      Restrictions.Or(
        Restrictions.On(() => fieldAlias.Parent).IsNull, // this is what we need
        Restrictions.On(() => parentFieldAlias.Value).IsLike(parentValue))
    );
    

    第一个解决方案的问题是,我们无法评估 浮动/虚拟对象是否为 null:parentFieldAlias

    .Where(() => (parentFieldAlias.Value == parentValue) || (parentFieldAlias == null)) ;

    我们需要检查所有者的财产:fieldAlias.Parent

    【讨论】:

    • 很公平,这是有道理的。很好地抓住了 IsNull。我会更正它并检查它是否按我的需要工作。
    • 再次感谢您发现我的错误。效果很好!
    【解决方案2】:

    我有类似的问题和条件之间的附加括号

    喜欢

    .Where(() => (parentFieldAlias.Value == parentValue) || (parentFieldAlias == null));
    

    让事情为我工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-25
      • 1970-01-01
      相关资源
      最近更新 更多