nhibernate - "Ambiguous column name"在集合映射中使用 order-by 时出现异常

标签 nhibernate

考虑这个代表层次结构中的节点的类:

public class Node
{
    public Node()
    {
        Children = new List<Node>();
    }

    public virtual int Id { get; set; }

    public virtual IList<Node> Children { get; set; }

    public virtual Node Parent { get; set; }

    public virtual int Position
    {
        get { return Parent == null ? -1 : Parent.Children.IndexOf(this); }
        set { }
    }
}

映射看起来像这样(因为 NHibernate 不支持双向关联中的列表,我在这里使用一个包并让子级自动确定它们的位置):

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="AmbiguousColumn" assembly="AmbiguousColumn" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Node">
    <id name="Id" type="Int32">
      <generator class="identity" />
    </id>
    <bag name="Children" inverse="true" cascade="all" order-by="Position">
      <key column="Parent" />
      <one-to-many class="Node" />
    </bag>
    <many-to-one name="Parent" />
    <property name="Position" />
  </class>
</hibernate-mapping>

要获取所有已加载子节点的节点,我将使用如下查询:

var nodes = session.QueryOver<Node>()
                   .Fetch(x => x.Children).Eager
                   .List();

但是,执行此操作会导致异常:

NHibernate.Exceptions.GenericADOException: could not execute query [...(sql)...] ---> System.Data.SqlClient.SqlException: Ambiguous column name 'Position'.

SQL:

SELECT
    this_.Id as Id0_1_,
    this_.Parent as Parent0_1_,
    this_.Position as Position0_1_,
    children2_.Parent as Parent3_,
    children2_.Id as Id3_,
    children2_.Id as Id0_0_,
    children2_.Parent as Parent0_0_,
    children2_.Position as Position0_0_
FROM
    Node this_
left outer join
    Node children2_
        on this_.Id=children2_.Parent
ORDER BY
    Position

我明白为什么会发生这种情况:NH 连接同一个表两次,但使用 order 子句而不限定列名。

问题是:我怎样才能让这个场景发挥作用?求助于 not 可能很困难,因为我想建立双向关系。

SO上有几个类似的问题,但我没有找到实际的解决方案。


更新:错误是特定于数据库/驱动程序的。使用 Sql Server CE(例如 SqlServerCeDriver 和 MsSqlCe40Dialect)我得到了正确的查询。使用 Sql Server(例如 Sql2008ClientDriver 和 MsSql2012Dialect)会产生不合格的查询。

根据我自己的测试,这种行为在github上的master分支中仍然存在。

带有测试用例的要点:https://gist.github.com/anonymous/5377535

最佳答案

我想我找到了问题的原因和可行的解决方法:

问题的原因是该列称为“Position”,根据http://msdn.microsoft.com/en-us/library/ms189822.aspx,它是 ODBC 中的保留字。

这与 NH 的 hbm2ddl.keywords 属性的默认值设置为“keywords”的事实相结合,以某种方式导致 NH 无法限定 order-by 子句,可能是因为它虽然“Position”是关键字,而不是列。

http://nhforge.org/blogs/nhibernate/archive/2009/06/24/auto-quote-table-column-names.aspx

修复方法:

1) 为属性使用不同的名称 - 一个不是关键字的名称。在这种情况下,PositionInParent 可以正常工作,没有任何问题。

2) 使用反引号正确引用 order by 子句。

<bag name="Children" inverse="true" cascade="all" order-by="`Position`">

或者您选择的 map API 中的任何内容,例如通过代码映射:

cls.Bag(x => x.Children,
        map =>
        {
            map.Inverse(true);
            map.Cascade(Cascade.All);
            map.Key(key => key.Column("Parent"));
            map.OrderBy("`Position`"); // note that you must not use a lambda expression in this case
        },
        map => map.OneToMany());

3) 禁用关键字自动导入,即。将 hbm2ddl.keywords 设置为 none(keywordsauto-quote 都不起作用):

<property name="hbm2ddl.keywords">none</property>

或者以编程方式:

config.DataBaseIntegration(db => db.KeywordsAutoImport = Hbm2DDLKeyWords.None);

您仍然可以在构建 session 工厂之前调用 SchemaMetadataUpdater.QuoteTableAndColumns 自动引用保留字。

SchemaMetadataUpdater.QuoteTableAndColumns(config);

我现在会坚持使用方法 3,因为它是迄今为止最轻松的。

关于nhibernate - "Ambiguous column name"在集合映射中使用 order-by 时出现异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15975513/

相关文章:

nhibernate - NHibernate中的SQL 2008 HierarchyID支持

NHibernate 2nd Level Cache - Membase MemCache - 多 session 工厂

.net - 在 nhibernate-mapping 中设置默认值

nhibernate 延迟加载使用隐式事务

c# - NHibernate 具有多个数据库和事务

c# - 使用虚拟属性支持 NHibernate 代理; ReSharper 警告构造函数中的虚拟成员调用

c# - 使用 nHibernate 在字段中存储逗号分隔的列表

NHibernate - 在 Dispose() 方法中使用 Session.Flush() - 好主意吗?

c# - 可以更改 NHibernate 的格式来制定绑定(bind)变量吗?

c# - nHibernate:无法解析属性