我有一个父表,即audit_log(parent),它包含一个列id。对于audit_log中的给定id,我有一个供应商ID列表。我将它们存储在单独的表audit_log_vendorid(子表)中。我希望子表从父表中获取id作为列之一(parent_id)。这是表格架构。
AUDIT_LOG
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| id | bigint(19) | NO | PRI | NULL | |
+-------+------------+------+-----+---------+-------+
audit_log_vendorid
+-----------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------+------+-----+---------+----------------+
| id | bigint(19) | NO | PRI | NULL | auto_increment |
| vendor_id | bigint(19) | NO | | NULL | |
| parent_id | bigint(19) | NO | | NULL | |
+-----------+------------+------+-----+---------+----------------+
我已经定义了我的hibernate类,如下所示
@Entity
@Table(name="audit_log")
public class AuditLog {
private List<AuditVendorPair> vendorIDs;
public AuditLog(List<AuditVendorPair> vendorIds) throws Exception {
this.vendorIDs = vendorIDs;
}
@OneToMany(cascade=CascadeType.ALL)
@JoinTable(name = "audit_log_vendorid",
joinColumns = { @JoinColumn(name = "parent_id", referencedColumnName="id") })
public List<AuditVendorPair> getVendors() {
return vendorIDs;
}
@Id @Column(name="ID")
public Long getId() {
return super.getId();
}
public void setHostServices(List<AuditVendorPair> vendorIDs){
this.vendorIDs = vendorIDs;
}
}
我的audit_log_vendorid的hibernate映射类如下所示。我传入了一个供应商ID,并期望其他两个字段由hibernate填充。我想从audit_log中的“id”字段获取parent_id字段。它现在被初始化为null,导致mysql约束异常。
@Entity
@Table(name="audit_log_vendorid")
public class AuditVendorPair {
private Long id;
private Long parent_id;
private Long vendor_id;
public AuditVendorPair(Long vendor_id){
this.vendor_id = vendor_id;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
}
@Column(name="vendor_id")
public Long getVendorID() {
return vendor_id;
}
public void setVendorID(Long vendor_id){
this.vendor_id = vendor_id;
}
@Column(name="parent_id")
public Long getParentId() {
return parent_id;
}
public void setParentId(Long parentID){
this.parent_id = parentID;
}
}
我很想知道我的注释是否正确。我基本上希望audit_log表中的id由hibernate填充在audit_log_vendorid表的parent_id字段中。
答案 0 :(得分:1)
不,他们不正确。 audit_log_vendorid
不是联接表。连接表是一个未映射到实体的表,它包含映射到其他表的两个关联实体的ID。
您还应该在AuditVendorPair中没有parent_id字段。不仅因为它不尊重Java命名约定,还因为它应该被对使用ManyToOne映射的AuditLog的引用所取代。
因此,简而言之,您应该有一个双向OneToMany关联,按照the documentation中的说明进行映射。
答案 1 :(得分:1)
我认为你忽略了JPA中的一个关键概念,即实体是对象,所以你永远不会有一个实体直接使用ID引用它的父,你会引用该对象(JPA将在查询时使用id DB)
@Entity
@Table(name="audit_log")
public class AuditLog {
@OneToMany(cascade= CascadeType.ALL, mappedBy = "auditLog")
private Collection<AuditVendorPair> vendorIDs;
@Id @Column(name="id")
private Long id;
public AuditLog() {
}
public Collection<AuditVendorPair> getVendors() {
if (vendorIDs == null) {
vendorIDs = new ArrayList<>();
}
return vendorIDs;
}
public long getId() {
return id;
}
}
和
@Entity
@Table(name = "audit_log_vendorid")
public class AuditVendorPair {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@JoinColumn(nullable = false, name = "parent_id")
@ManyToOne(optional = false)
private AuditLog auditLog;
@Column(name = "vendor_id")
private Long vendorId;
public AuditVendorPair() {
}
public long getVendorId() {
return vendorId;
}
public void setVendorId(long vendorId) {
this.vendorId = vendorId;
}
public AuditLog getAuditLog() {
return auditLog;
}
public void setAuditLog(AuditLog auditLog) {
this.auditLog = auditLog;
}
}
AuditVendorPair使用Entity引用AuditLog,由于这是一个实体关系,您必须使用@JoinColumn来指定名称。
JPA / Hibernate的一些最佳实践
答案 2 :(得分:0)
听起来你应该多读一些关于JPA背后的原理。 这是一个&#39; raw&#39; JPA代码示例的例子,如果你使用Spring-data和autowire @PersistanceUnit,你不需要自己管理entityManager。
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PU-Name");
EntityManager em = emf.createEntityManager();
try {
long primaryKey = 1L; // comes from somewhere else
long vendorId = 1L; // comes from somewhere
AuditLog log = em.find(AuditLog.class, primaryKey); // loaded from DB
AuditVendorPair pair = new AuditVendorPair();
pair.setAuditLog(log);
pair.setVendorId(vendorId);
em.getTransaction().begin();
em.persist(pair);
em.getTransaction().commit();
} finally {
em.close();
}
您必须在代码中连接实体,并且必须从数据库加载任何现有实体。如果要存储新的AuditVendorPair,首先必须加载AuditLog对象,然后在新创建的AuditVendorPair上设置它。通常,供应商也将是一个实体,因此也必须查找它。
注意:上述示例不维护AuditLog和AuditVendorPair之间的双向关系,因为AuditVendorPair未添加到AuditLog上的供应商集合中。由于定义关系的列位于AuditVendorPair(存储)上,因此这不是问题,因为下次从数据库加载AuditLog实例时,AuditVendorPair将成为供应商集合的一部分。但是,如果在关闭持久性上下文后使用AuditLog,则可能需要保持双向关系。
注意:上面的示例假设您获得了主键请求。通常,您不应在任何前端公开主键,在我们的系统中,我们为UI中公开的每个实体生成唯一字段(UUID)。