【问题标题】:Cascade persist JPA entities with unknown PK/FK attributes violates NotNullConstraint具有未知 PK/FK 属性的级联持久 JPA 实体违反 NotNullConstraint
【发布时间】:2015-09-17 09:37:27
【问题描述】:

我想保留一个具有许多 1:1 或 1:many 关系的 JPA 实体,只需一次调用 persist

问题:实体的主键是自动生成的,并在子实体中用作外键。提交事务时,有一个异常指出子实体的外键列上违反了 NotNullConstraint。

内部异常:java.sql.SQLException:ORA-01400:插入 ("SCHEMA"."PROTOCOL_FILE"."PROTOCOL_ID") 中的 NULL 不可能

父实体:

@Entity
@Table(name = "...")
public class Protocol {

    @Id
    @GeneratedValue(generator="SQ_PROTOCOL", strategy=GenerationType.SEQUENCE)
    @SequenceGenerator(name="SQ_PROTOCOL", sequenceName="SQ_PROTOCOL", allocationSize=50)
    @Column(name = "PROTOCOL_ID")
    private Long protocolId;

    @OneToOne(mappedBy="protocol", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private ProtocolFile file;

    //Other attributes and getter/setter omitted
}

子实体:

@Entity
@Table(name = "PROTOCOL_FILE")
public class ProtocolFile {

    @Id
    @Column(name = "PROTOCOL_ID")
    private Long protocolId;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumns(@JoinColumn(name="PROTOCOL_ID", referencedColumnName="PROTOCOL_ID", updatable=false, insertable=false))
    private Protocol protocol;

    //Other attributes and getter/setter omitted
}

你知道一个方便的解决方案,这样我就可以在一次调用中持久化所有属于 Protocol 的实体吗?

【问题讨论】:

  • 你为什么使用@JoinColumns?你试过没有它吗?
  • @David_Ware 当我删除@JoinColumns 时,插入语句看起来像INSERT INTO PROTOCOL_FILE(PROTOCOL_ID, ....., PROTOCOL_PROTOCOL_ID) VALUES (?, ...... , ?) bind => [null, ........ , 3351]。如您所见,插入语句使用了正确的 ID,但它正在寻址一个不存在的表列。

标签: java jpa eclipselink


【解决方案1】:

这里的情况是ProtocolFile 的“派生身份”-ProtocolFile 的 ID 是 Protocol 的 ID,它们之间存在一对一的关系。

我看到您正在使用updatable=false, insertable=false,但最好遵循建议使用@MapsId 注释的规范:

@Entity
@Table(name = "PROTOCOL_FILE")
public class ProtocolFile {

    @Id // No @Column here
    private Long protocolId;

    @MapsId // --- HERE
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="PROTOCOL_ID") // Just that
    private Protocol protocol;
}

或者您可能想完全跳过protocolId 字段,并将@Id 注释放在关系上。

@Entity
@Table(name = "PROTOCOL_FILE")
public class ProtocolFile {

    @Id // --- HERE
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="PROTOCOL_ID") // Just that
    private Protocol protocol;
}

当然,您需要在创建过程中将protocol 实例设置为file,以后不要再更改它(例如,只允许使用ProtocolFile 构造函数进行设置)。

有关更多详细信息和示例,请参阅JPA 2.0 spec 的“2.4.1 与派生身份对应的主键”部分(示例 4 似乎是您的情况)。

【讨论】:

  • 非常感谢。这似乎可以识别并解决问题。
猜你喜欢
  • 2013-10-26
  • 2018-05-15
  • 2015-11-02
  • 2019-12-08
  • 2012-06-17
  • 1970-01-01
  • 1970-01-01
  • 2015-09-09
  • 1970-01-01
相关资源
最近更新 更多