首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在集合映射中使用order-by时的“歧义列名”异常

在集合映射中使用order-by时的“歧义列名”异常
EN

Stack Overflow用户
提问于 2013-04-12 15:38:25
回答 1查看 1.4K关注 0票数 2

考虑这个类,它表示一个层次结构中的节点:

代码语言:javascript
复制
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不支持双向关联中的列表,我在这里使用一个袋子,让孩子自动确定他们的位置):

代码语言:javascript
复制
<?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>

要加载所有带子节点的节点,我需要使用如下查询:

代码语言:javascript
复制
var nodes = session.QueryOver<Node>()
                   .Fetch(x => x.Children).Eager
                   .List();

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

NHibernate.Exceptions.GenericADOException:无法执行查询.-> System.Data.SqlClient.SqlException:模棱两可的列名“位置”。

SQL:

代码语言:javascript
复制
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子句而不限定列名。

问题是:我如何才能让这个场景发挥作用?诉诸替代可能是困难的,因为我想有一个双向关系。

有几个类似的问题,但我没有找到一个实际的解决办法。

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

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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-13 09:25:44

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

造成此问题的原因是该列被称为“位置”,根据http://msdn.microsoft.com/en-us/library/ms189822.aspx,它是ODBC中的一个保留字。

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

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

解决问题的方法:

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

( 2)适当地使用倒带字句引用定单。

代码语言:javascript
复制
<bag name="Children" inverse="true" cascade="all" order-by="`Position`">

或者在您选择的映射API中所使用的任何内容,例如,在通过代码进行映射时:

代码语言:javascript
复制
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都不起作用):

代码语言:javascript
复制
<property name="hbm2ddl.keywords">none</property>

或以编程方式:

代码语言:javascript
复制
config.DataBaseIntegration(db => db.KeywordsAutoImport = Hbm2DDLKeyWords.None);

您仍然可以在构建会话工厂之前调用SchemaMetadataUpdater.QuoteTableAndColumns自动引用保留的单词。

代码语言:javascript
复制
SchemaMetadataUpdater.QuoteTableAndColumns(config);

现在,我将坚持使用方法3,因为它是迄今为止最无痛的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15975513

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档