简体   繁体   English

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

[英]JPA2: Nested Primary Key class cannot persist as binding null

I'm using JPA 2.x with EclipseLink 2.5.1 with nested primary key class as the following: - 我正在将JPA 2.x与带有nested primary key class EclipseLink 2.5.1结合使用,如下所示:-

Note: The behind the scene environment 注意:幕后环境

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

The Master PK 大师PK

@Embeddable
public class MasterPk {
    @Column(
        name   = "MASTER_ID",
        length = 5
    )
    private String masterId;

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

The Master 大师

@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
}

The Detail PK 细节PK

@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
}

The Detail 细节

@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
}

The coding for persisting the Detail 持久化细节的编码

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);

The persistence XML 持久性XML

<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>

When the project starts, all tables are created correctly, especially the primary key and foreign key . 项目启动时,将正确创建所有表,尤其是primary keyforeign key But when persist with the coding., there are some trouble about the Detail as the Detail.masterId.id is null. 但是当persist进行编码时,由于Detail.masterId.id为null,所以会有一些关于Detail麻烦。 The EclipseLink shows me as EclipseLink我显示为

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))
                                            )
                                )
                         )

I double check by printing all field in this object-graph and can confirm that the masterId is not null as well. 我通过打印此object-graph所有field进行仔细检查,并可以确认masterId也不为null。 I'm not sure if doing something wrong/misunderstanding. 我不确定是否做错了/误解。 Could you please help to advise how to solve this issue? 您能帮忙建议如何解决此问题吗?

Edit 1 编辑1

  1. Fix the @ManyToOne at the Detail.java . Detail.java处修复@ManyToOne It is a typo when copying and pasting to this question 复制并粘贴到此问题时出现错字
  2. Try to add the @Embedded to the masterId at the class DetailPk . 尝试将添加@EmbeddedmasterId在类DetailPk

    Edit 1 result still faces the same issue. 编辑1结果仍然面临相同的问题。

Edit 2 编辑2

  1. Add the coding for create the detail and persist 添加用于创建detailpersist
  2. I create the MasterPk directly without finding the Master . 我直接创建MasterPk而不找到Master

    Further question, Should I need to find the Mater entity for getting its id and assigning it to the DetailPk instead of create it directly via new MasterPk(); 进一步的问题,我是否需要找到Mater实体以获取其id并将其分配给DetailPk而不是直接通过new MasterPk();直接创建它new MasterPk(); ?

As MasterPK is an embeddable it should be annotated with @Embedded : 由于MasterPK是可嵌入的,因此应使用@Embedded进行注释:

@Embeddable
public class DetailPk {

    @Embedded
    private MasterPk masterId;
    ...
}

I guess Detail entity is also missing @ManyToOne (or it's just intentional?) 我猜Detail实体也缺少@ManyToOne (或者只是故意的?)

@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 Edit 2 广告修改2

The following statement 以下声明

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

means that the owning side of the master-detail relationship (represented by @ManyToOne association) is null. 表示主从关系的拥有方 (由@ManyToOne关联表示)为null。 From JPA point of view this looks as follows: 从JPA的角度来看,它如下所示:

  • MASTER_ID column is related to master field in Detail entity MASTER_ID列与Detail实体中的master字段相关
  • Master entity uses MasterPK as the primary key Master实体使用MasterPK作为主键
  • Detail entity references Master with master field Detail实体引用Mastermaster现场
  • because Detail entity acts as the owner of the relationship it would be good to specify cascading on it, ie @ManyToOne(cascade = CascadeType.PERSIST) 因为Detail实体充当关系的所有者,所以最好在其上指定级联,即@ManyToOne(cascade = CascadeType.PERSIST)

Based on the above, to make thing work we would need to set up the owning side , for example: 基于上述内容,要使工作正常,我们需要设置所有者方 ,例如:

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);

This will result in: 这将导致:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM