问题描述
我想坚持一个有很多1:1或1:多关系的JPA实体,只有一次调用 persist
。
I would like to persist a JPA entity with many 1:1 or 1:many relationships with only one call to persist
.
问题:实体的主键是自动生成的,并用作子实体中的外键。提交事务时,会在子实体的外键列上指出违反NotNullConstraint的异常。
Problem: the entity's primary key is auto generated and used as a foreign key in a child entity. When the transaction is committed, there is an exception pointing out a violated NotNullConstraint on the child entity's foreign key column.
父实体:
@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
}
您是否知道一个方便的解决方案,所以我可以在一次通话中保留属于协议
的所有实体?
Do you know a convenient solution, so I can persist all entities, that belong to Protocol
, in one call?
推荐答案
这里的情况是 ProtocolFile
的派生身份 - 的ID ProtocolFile
是协议
的ID,它们之间存在一对一的关系。
The situation you have here is a "derived identity" of the ProtocolFile
- the ID of the ProtocolFile
is the ID of the Protocol
and there is a one-to-one relationship between them.
我看到你正在使用 updatable = false,insertable = false
但是最好遵循建议使用 @MapsId的规范
注释:
I see you are using updatable=false, insertable=false
but it's better to follow the specs which suggest to use the @MapsId
annotation:
@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
注释。
Or you may want to skip the protocolId
field altogether and put the @Id
annotation on the relationship.
@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;
}
当然,您需要设置协议
创建期间文件
的实例,不再在以后更改(例如,仅允许使用 ProtocolFile constructor)。
Of course, you need to set the protocol
instance to the file
during creation and not change it later any more (eg. allow to set it only using the ProtocolFile
constructor).
请参阅了解更多详细信息和示例(示例4 似乎是你的情况)。
See section "2.4.1 Primary Keys Corresponding to Derived Identities" of the JPA 2.0 spec for more details and examples (Example 4 seems to be your case).
这篇关于具有未知PK / FK属性的级联持久性JPA实体违反NotNullConstraint的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!