首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JPA2:嵌套主键类不能作为绑定null持久化

JPA2:嵌套主键类不能作为绑定null持久化
EN

Stack Overflow用户
提问于 2014-12-04 08:21:59
回答 1查看 850关注 0票数 1

我将JPA 2.xEclipseLink 2.5.1nested primary key class一起使用,具体如下:

注:场景背后的环境

代码语言:javascript
复制
1. OS: Windows 7 64 Bits
2. JDK: 1.7.0_65 64 Bits
3. Maven: 3.2.2
4. Arquillian: 1.1.5.Final
5. Container: Glassfish 4 embedded
6. Database: Derby 10.10.2.0 embedded

大师PK

代码语言:javascript
复制
@Embeddable
public class MasterPk {
    @Column(
        name   = "MASTER_ID",
        length = 5
    )
    private String masterId;

    //----> Setter/Getter is omitted
}

大师

代码语言:javascript
复制
@Entity
@Table(name = "MASTER_TAB")
public class Master {

    @EmbeddedId
    private MaskerPk id;

    @Column(
        name   = "MASTER_NAME",
        length = 40
    )
    private String masterName;

    @OneToMany(
        mappedBy = "master"
    )
    private List<Detail> details;

    //----> Setter/Getter is omitted
}

细节PK

代码语言:javascript
复制
@Embeddable
public class DetailPk {

    //----> THE NESTED IS HERE.
    @Embedded
    private MasterPk masterId;

    @Column(
        name   = "DETAIL_ID",
        length = 5
    )
    private String detailId;

    //----> Setter/Getter is omitted
}

细节

代码语言:javascript
复制
@Entity
@Table(name = "DETAIL_TAB")
public class Detail {

    @EmbeddedId
    private DetailPk id;

    @Column(
        name   = "DETAIL_NAME",
        length = 40
    )
    private String detailName;

    @MapsId("masterId")
    @ManyToOne
    @JoinColumns({
        @JoinColumn(
            name                 = "MASTER_ID",
            referencedColumnName = "MASTER_ID",
            nullable             = false
        )
    })
    private Master master;

    //----> Setter/Getter is omitted
}

持久化细节编码

代码语言:javascript
复制
MasterPk masterPk = new MasterPk();
masterPk.setId("001"); //there is a 001 existed in the db

DetailPk detailPk = new DetailPk();
detailPk.setMasterId(masterPk);
detailPk.setDetailId("001"); //new detail to persist

Detail detail = new Detail();
detail.id(detailPk);
detail.setDetailName("detail-name");

em.persist(detail);

持久性XML

代码语言:javascript
复制
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
                   http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="unittest" transaction-type="JTA">

        <jta-data-source>jdbc/unittest</jta-data-source>

        <class>com.test.MasterPk</class>
        <class>com.test.Master</class>
        <class>com.test.DetiailPk</class>
        <class>com.test.Detail</class>

        <exclude-unlisted-classes>true</exclude-unlisted-classes>

        <properties>
            <property name="eclipselink.ddl-generation" 
                      value="create-tables" />                     
            <property name="eclipselink.ddl-generation.output-mode"
                      value="both"/>
            <property name="eclipselink.application-location" 
                      value="target"/>                     
            <property name="eclipselink.create-ddl-jdbc-file-name" 
                      value="createDDL_ddlGeneration.jdbc"/>
            <property name="eclipselink.drop-ddl-jdbc-file-name" 
                      value="dropDDL_ddlGeneration.jdbc"/>
        </properties>

    </persistence-unit>
</persistence>

当项目启动时,所有表都会正确创建,特别是primary keyforeign key。但是,当persist进行编码时,Detail会出现一些问题,因为Detail.masterId.id是空的。EclipseLink向我展示了

代码语言:javascript
复制
Column 'MASTER_ID' cannot accept a NULL value.

INSERT INTO DETAIL_TAB (DETAILE_NAME, DETAIL_ID, MASTER_ID)
VALUES (?, ?, ?)
bind => [detail-name, 001, null]

//
//----> We may be noticed that the masterId is not null. It is printed as 001.
//
Query: InsertObjectQuery(Detail(detailName=detail-name,
                                id=DetailPk(detailId=001,
                                            masterId=(MasterPk(masterId=001))
                                            )
                                )
                         )

我通过在此field中打印所有object-graph来进行双重检查,并且可以确认masterId也不是null。我不确定是否做错了什么/误解了什么。你能帮我建议如何解决这个问题吗?

编辑1

  1. 修复@ManyToOneDetail.java上。在复制和粘贴这个问题时,这是一个错误。
  2. 尝试将@Embedded添加到类DetailPkmasterId中。 编辑1结果仍然面临相同的问题。

编辑2

  1. 添加用于创建detailpersist的代码
  2. 我直接创建MasterPk,而没有找到Master。 进一步的问题是,我是否需要找到Mater实体来获取其id并将其分配给DetailPk,而不是直接通过new MasterPk();创建它?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-12-05 18:34:50

由于MasterPK是可嵌入的,所以应该用@Embedded对其进行注释

代码语言:javascript
复制
@Embeddable
public class DetailPk {

    @Embedded
    private MasterPk masterId;
    ...
}

我猜Detail实体也缺少@ManyToOne (还是故意的?)

代码语言:javascript
复制
@Entity
@Table(name = "DETAIL_TAB")
public class Detail {
    ...
    @MapsId("masterId")
    @ManyToOne
    @JoinColumns({
        @JoinColumn(
            name                 = "MASTER_ID",
            referencedColumnName = "MASTER_ID",
            nullable             = false
        )
    })
    private Master master;
}

Ad 编辑2

以下陈述

代码语言:javascript
复制
INSERT INTO DETAIL_TAB (DETAILE_NAME, DETAIL_ID, MASTER_ID)
VALUES (?, ?, ?)
bind => [detail-name, 001, null]

意味着主细节关系(由@ManyToOne关联表示)的拥有方为空。从JPA的角度来看,这看起来如下:

  • MASTER_ID列与Detail实体中的master字段相关。
  • Master实体使用MasterPK作为主键
  • Detail实体使用master字段引用Master
  • 因为Detail实体充当关系的所有者,所以最好在其上指定级联,即@ManyToOne(cascade = CascadeType.PERSIST)

基于以上所述,为了使事物正常工作,我们需要设置拥有方,例如:

代码语言:javascript
复制
Master master = new Master();
master.id(masterPk);    

Detail detail = new Detail();
detail.id(detailPk);
detail.setMaster(master); // the owning side of the master-detail relationship

master.setDetail(detail); // mandatory if CascadeType.PERSIST is not defined
em.persist(detail);

这将导致:

代码语言:javascript
复制
INSERT INTO DETAIL_TAB (DETAIL_NAME, DETAIL_ID, MASTER_ID)
VALUES (?, ?, ?)
bind => [detail-name, 001, 001]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27289243

复制
相关文章

相似问题

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