Hibernate重复列异常 - 为一对多相关实体声明两次'username'

时间:2012-03-26 16:03:42

标签: hibernate mapping one-to-many

得到了经典的Hibernate问题:

Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: entry.Authority column: username (should be mapped with insert="false" update="false")

users.hbm.xml:

<class name="entry.User" table="users">
    <property name="username" column="username"/>
    <set name="authorities" table="authorities" lazy="false" cascade="all">
        <key column="username" not-null="true"/>
        <one-to-many class="entry.Authority"/>
    </set>

authorities.hbm.xml:

    <class name="entry.Authority" table="authorities">
        <id name="id"/>
        <property name="username" column="username"/>
    </class>

尝试过经典解决方案:

<property name="username" column="username"  insert="false" update="false"/>

GOT:

java.sql.BatchUpdateException: Field 'username' doesn't have a default value

为什么我不能在.xml中指定username两次?
据我了解,此声明<property name="username" column="username"/>User有关,<key column="username" not-null="true"/>Authorities有关。那么为什么会发生冲突?如何解决?最小入侵?

编辑:

    <class name="entry.User" table="users">
        <id name="id">
            <generator class="increment" />
        </id>
        <property name="username" column="username"/>     
        <set name="authorities" table="authorities" lazy="false" cascade="all" inverse="true">
            <key column="username" not-null="true"/>
            <one-to-many class="entry.Authority"/>
        </set>
...

<class name="entry.Authority" table="authorities">
    <id name="id"/>
    <property name="username" column="username"/>
    <property name="authority" column="authority"/>
    <many-to-one name="user" class="entry.User">
             <column name="username"/>
     </many-to-one>
</class>

3 个答案:

答案 0 :(得分:2)

使用users.hbm.xml <key column="username" not-null="true"/>中的密钥定义,您已经在权限中处理列用户名。 authority.hbm.xml中的行<property name="username" column="username"/>是多余的,即使在多对一中使用也是如此。每次加载/更新或插入权限实例通过用户时,该字段由Hibernate自动处理。如果您还在authorities.hbm.xml中定义了该字段,那么它会被设置两次 - 这就是您收到错误消息的原因。

如果由于某些特殊原因,你真的想在authorities.hbm.xml中拥有用户名,那么你必须指定insert / update = false(就像你已经做过的那样)和一个默认值来避免你的错误信息(甚至如果从未使用默认值)。例如

<property name="username" insert="false" update="false">
  <column="username" default="anyValue"/>
</property>

但我只想推荐一下:

<class name="entry.Authority" table="authorities">
  <id name="id"/>
  <property name="authority" column="authority"/>
  <many-to-one name="user" class="entry.User">
         <column name="username"/>
   </many-to-one>
</class>

在您发表评论后添加:

现在我在新映射中看到一个问题:<key>元素必须引用父表的键,而事实并非如此。 Users表中的键是id,但您使用普通属性Username作为Authority中的外键。有两种方法可以解决这个问题:

1)使用户名成为用户的密钥(删除列ID并在用户中将密钥定义为

<id name="username">
 <column="username"/>
</id>

(我不确定在这种情况下,在新的Authority实例中,hibernate会自动设置成员用户名还是必须手动设置。)

新:以下是完整的映射(未经测试):

<class name="entry.User" table="users">
  <id name="username" type="String">
    <column="username"/>
  </id>
  <property name="password" column="password" type="String"/>
  <property name="enabled" column="enabled" type="boolean"/>

  <set name="authorities" table="authorities" lazy="false" cascade="all" inverse="true">
    <key column="username" not-null="true"/>
    <one-to-many class="entry.Authority"/>
  </set>
</class>

2)你将id作为权限中的外键: 在users.hbm.xml

<key column="id" not-null="true"/>

,并在authority.hbm.xml中用

替换列用户名
<property name="userId" column="userId"/>

您还必须修改数据库表。

答案 1 :(得分:1)

错误似乎来自权威映射。将其更改为具有反向引用

编辑:您可以使用propertyref告诉H加入另一个属性

<class name="entry.Authority" table="authorities">
    <id name="id"/>
    <many-to-one name="user" column="username" property-ref="username"/>
</class>

and 

<set name="authorities" inverse="true" property-ref="username">

答案 2 :(得分:0)

如果使用JPA语法将是这样的(使拥有方不可更新): -

@JoinColumn(name = "", referencedColumnName = "", insertable = false, updatable = false)

问题是双向关系尝试再次更新列