【问题标题】:How can I map "insert='false' update='false'" on a composite-id key-property which is also used in a one-to-many FK?如何将“insert='false' update='false'”映射到也用于一对多 FK 的复合 ID 键属性上?
【发布时间】:2011-06-21 01:05:25
【问题描述】:

我正在使用现有数据库架构处理遗留代码库。现有代码使用 SQL 和 PL/SQL 在 DB 上执行查询。我们的任务是使项目的一小部分数据库引擎不可知(起初,最终改变一切)。我们选择使用 Hibernate 3.3.2.GA 和“*.hbm.xml”映射文件(而不是注释)。不幸的是,更改现有架构是不可行的,因为我们无法回归任何遗留功能。

我遇到的问题是,当我尝试映射单向、一对多关系时,FK 也是复合 PK 的一部分。这是类和映射文件...

CompanyEntity.java

public class CompanyEntity {
    private Integer id;
    private Set<CompanyNameEntity> names;
    ...
}

公司名称实体.java

public class CompanyNameEntity implements Serializable {
    private Integer id;
    private String languageId;
    private String name;
    ...
}

公司名称实体.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.example">

    <class name="com.example.CompanyEntity" table="COMPANY">
        <id name="id" column="COMPANY_ID"/>
        <set name="names" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
            <key column="COMPANY_ID"/>
            <one-to-many entity-name="vendorName"/>
        </set>
    </class>

    <class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
        <composite-id>
            <key-property name="id" column="COMPANY_ID"/>
            <key-property name="languageId" column="LANGUAGE_ID"/>
        </composite-id>
        <property name="name" column="NAME" length="255"/>
    </class>

</hibernate-mapping>

此代码适用于具有名称的公司的 SELECT 和 INSERT。当我尝试更新和现有记录时遇到问题。我收到了 BatchUpdateException,在查看 SQL 日志后,我看到 Hibernate 正在尝试做某事愚蠢...

update COMPANY_NAME set COMPANY_ID=null where COMPANY_ID=?

Hibernate 试图在更新子记录之前解除关联。问题是该字段是 PK 的一部分并且不可为空。我发现让 Hibernate 不这样做的快速解决方案是将“not-null='true'”添加到父映射中的“key”元素。所以现在可能映射看起来像这样......

公司名称实体.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.example">

    <class name="com.example.CompanyEntity" table="COMPANY">
        <id name="id" column="COMPANY_ID"/>
        <set name="names" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
            <key column="COMPANY_ID" not-null="true"/>
            <one-to-many entity-name="vendorName"/>
        </set>
    </class>

    <class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
        <composite-id>
            <key-property name="id" column="COMPANY_ID"/>
            <key-property name="languageId" column="LANGUAGE_ID"/>
        </composite-id>
        <property name="name" column="NAME" length="255"/>
    </class>

</hibernate-mapping>

这个映射给出了异常...

org.hibernate.MappingException: Repeated column in mapping for entity: companyName column: COMPANY_ID (should be mapped with insert="false" update="false")

我现在的问题是我尝试将这些属性添加到 key-property 元素,但 DTD 不支持。我也尝试将其更改为键多对一元素,但这也不起作用。所以...

如何将“insert='false' update='false'”映射到也用于一对多 FK 的复合 ID 键属性上?

【问题讨论】:

  • 在查看了 Hibernate 注释文档之后,看起来我可以使用 JPA/Hibernate 注释创建所需的映射。我将对此进行更多试验并发布我的结果。
  • 我试图指定的映射不可能使用 *.hbm.xml 文件。实现这一点的唯一方法是使用下面 mcyalcin 的答案中提到的注释。
  • 我猜这个帖子可能会解决XML配置中的问题,stackoverflow.com/questions/9381029/…
  • @DinoTw 你的链接提示真的很有用。标记“inverse=true”确实可以让具有复合键的表负责更新和插入,解决了XML映射中的问题。

标签: hibernate-mapping hbm hibernate-onetomany hbmxml


【解决方案1】:

我认为您正在寻找的注释是:

public class CompanyName implements Serializable {
//...
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID", insertable = false, updatable = false)
private Company company;

您应该能够在 hbm.xml 中使用类似的映射,如下所示(在 23.4.2 中):

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/example-mappings.html

【讨论】:

  • 感谢您的回答。在您提供的 JBoss 文档链接中,它不包含任何我遇到问题的案例示例。我尝试完全按照它们显示的方式使用映射,但它仍然对我不起作用。看来,我试图完成的特定映射对于当前的 HBM DTD 规范是不可能的。话虽如此,您使用注释的解决方案不会遇到我遇到的相同问题,因此对于可以选择使用注释的任何人来说,这都是一个很好的解决方案。我通常会向所有有选择的人推荐注释。
  • 有趣。到目前为止,我只在 Hibernate 中使用了注解,发现这样更方便,但我认为注解功能是 xml 映射定义的子集,而不是相反。我将摆弄 xml,因为如果确实缺少功能,则应报告错误。我很高兴答案有所帮助!
  • 但是如果我想插入和更新,有没有其他方法可以解决这个问题?因为我想, insertable = false 和 updatable=false 将不允许我更改“公司”。
  • 如果您不想在CompanyName 中引用Company 对象怎么办?我的意思是,CompanyName 只是一个值,并且关系已经由one-to-many 定义。在CompanyName 中拥有Company 属性完全没有意义。
  • CompanyName 只是一个例子。如果您正在使用的对象真的“只是一个值”,那么您没有表/类,您可以向父对象添加一个列/字段并完成它。
【解决方案2】:

“Dino TW”提供了评论Hibernate Mapping Exception : Repeated column in mapping for entity的链接,其中包含重要信息。

链接提示在集合映射中提供“inverse=true”,我试过了,它确实有效。 Set 和 Composite 键结合在一起的情况非常罕见。使inverse=true,我们将使用复合键的表的插入和更新留给自己处理。

下面可以是需要的映射,

<class name="com.example.CompanyEntity" table="COMPANY">
    <id name="id" column="COMPANY_ID"/>
    <set name="names" inverse="true" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
        <key column="COMPANY_ID" not-null="true"/>
        <one-to-many entity-name="vendorName"/>
    </set>
</class>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多