【问题标题】:JPA unidirectional one-to-many relationship persistJPA 单向一对多关系持续存在
【发布时间】:2017-02-07 18:40:53
【问题描述】:

我正在尝试保持 3 个具有一对多关系的实体,但我无法做到正确。 这就是我所拥有的:

@Entity
@Table(name = "tb_person")
public class Person {
    @Id
    @SequenceGenerator(name = "my_seq", sequenceName = "pk_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq")
    @Column(name="person_id")
    private long personId;

    @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name = "person_id", referencedColumnName = "person_id")
    private List<Phone> phones;
}


@Entity
@IdClass(PersonBrandId.class)
@Table(name = "tb_person_phone")
public class Phone {
     @Id
     @Column(name = "retailer_id")
     private long personId;

     @Id
     @Column(name = "brand_code")
     private String brandCode;

     @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
     @JoinColumns({
        @JoinColumn(name = "brand_code", referencedColumnName = "brand_code", insertable = false, updatable = false),
        @JoinColumn(name = "person_id", referencedColumnName = "person_id", insertable = false, updatable = false)})
     List<Mobile> mobiles;

     ...other fields...
}

@Entity
@Table(name = "tb_mobile")
public class Mobile {
    @Id
    @SequenceGenerator(name = "my_seq2", sequenceName = "pk_seq2", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq2")
    @Column(name="mobile_id")
    private long mobileId;

    @Column(name = "person_id")
    private long personId;

    ...other fields...
}

所以,我想要实现的是仅持久化 Person,因为级联,Phone 和 Mobile 将自动持久化。 示例:

Person person = new Person();
Phone phone = new Phone();
Mobile mobile = new Mobile();
phone.getMobiles().add(mobile);
person.getPhones().add(phone);

em.persist(person);

问题是我收到一条错误消息,说 tb_person_phone.person_id 不能为空。

关系是单向的,所以我没有添加 ManyToOne。

为了回答一些评论:

  1. 我只使用 JPA
  2. 关系如下:

    一个人可以有多个电话。

    手机有复合主键:

       - person_id in Person
    
       - brand_code in Brand (a table with a list of brands)
    

    手机有主键:mobile_id

      has two FK:
    
       - person_id and brand_code both referencing the table Phone 
    

生成表格的 SQL:

CREATE TABLE "TB_PERSON"
(   "PERSON_ID" NUMBER NOT NULL ENABLE, 
"PERSON_NAME" VARCHAR2(100 BYTE) NOT NULL ENABLE, 
 CONSTRAINT "PERSON_PK" PRIMARY KEY ("PERSON_ID")
);


CREATE TABLE "TB_PERSON_PHONE" 
(   "PERSON_ID" NUMBER NOT NULL ENABLE, 
    "BRAND_CODE" VARCHAR2(30 BYTE) NOT NULL ENABLE, 
    "ATTR1" VARCHAR2(1 BYTE), 
    "ATTR2" VARCHAR2(100 BYTE), 
 CONSTRAINT "PERSON_PHONE_PK" PRIMARY KEY ("PERSON_ID", "BRAND_CODE")
 FOREIGN KEY ("PERSON_ID")
  REFERENCES "TB_PERSON" ("PERSON_ID") ENABLE, 
 FOREIGN KEY ("BRAND_CODE")
  REFERENCES "TB_BRAND" ("BRAND_CODE") ENABLE
);


CREATE TABLE "TB_MOBILE" 
(   "MOBILE_ID" NUMBER NOT NULL ENABLE, 
"PERSON_ID" NUMBER NOT NULL ENABLE, 
"BRAND_CODE" VARCHAR2(30 BYTE) NOT NULL ENABLE, 
"NUMBER" VARCHAR2(30 BYTE) NOT NULL ENABLE, 
"ATTR1" VARCHAR2(100 BYTE), 
"ATTR2" VARCHAR2(100 BYTE), 
 CONSTRAINT "MOBILE_PK" PRIMARY KEY ("MOBILE_ID"),
 CONSTRAINT "MOBILE_UQ" UNIQUE ("NUMBER", "PERSON_ID", "BRAND_CODE")
 USING INDEX (CREATE UNIQUE INDEX "MOBILE_UQ_IDX" ON "TB_MOBILE" ("NUMBER",       "PERSON_ID", "BRAND_CODE"),
 FOREIGN KEY ("PERSON_ID", "BRAND_CODE")
  REFERENCES "TB_PERSON_PHONE" ("PERSON_ID", "BRAND_CODE") ENABLE
 );

【问题讨论】:

  • 你是使用 Hibernate 和 JPA 还是只使用 JPA?
  • 您如何想象在电话中设置 personId 和 brandCode?从建模的角度来看,人 手机不是多对多关系,手机应该有品牌吗??
  • 正如我在之前的评论中指出的,您的代码存在根本缺陷。 Phone 中的两个 ID 字段不能被神奇地设置。除此之外,我不了解您的模型或数据库架构。

标签: java jpa one-to-many cascade


【解决方案1】:

为 Mobile 和 Phone 实体的主键设置 @GeneratedValue(strategy = GenerationType.AUTO)

【讨论】:

  • 你能分享这三个表的 sql 查询吗,我很容易调试。 @user1341300
  • 我添加了生成表的sql
【解决方案2】:

您在电话类中使用人员 ID 作为标识符

@Id
 @Column(name = "retailer_id")
 private long personId;

将另一列作为 Id 并添加一些生成 id 策略或

 Person person = new Person();

 em.persist(person); //<

 Phone phone = new Phone();
 Mobile mobile = new Mobile();
 phone.getMobiles().add(mobile);
 person.getPhones().add(phone);

 phone.setPersonId(person.getId()); // <

 em.persist(person);

【讨论】:

  • 这意味着我必须先持久化 Person ,然后再调用 em
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 2012-09-27
  • 2010-12-20
  • 2013-12-04
  • 2023-03-20
相关资源
最近更新 更多