在保留与其子实体具有 OneToMany 关系的父 JPA 实体时遇到问题。使用 EclipseLink 保存父实体时,父实体和子实体都保存到各自的表中,但链接回父实体的子表中的外键保留为空,从而破坏了数据库中的关系。
具体来说,问题出在application_address表上。我无法在 TblApplicationAdress 和 TblApplicationMembership 之间获得正确的配置,以便 JPA 将 application_membership_id 外键链接保存到 application_address 表中。 (就上下文而言,一个应用程序包含一个成员资格,其中包含许多地址。)
以下是我的设置的详细信息:
表格:
create table application
(
application_id bigserial primary key,
application_membership_id bigint references application_membership,
application_reference_number varchar,
-- other fields...
);
create table application_membership
(
application_membership_id bigserial primary key,
membership_reference_number varchar,
-- other fields...
);
create table application_address
(
application_address_id bigserial primary key,
application_membership_id bigint references application_membership,
address_type_code varchar,
address_line1_number varchar,
-- other fields...
);
JPA 实体:
@Getter
@Setter
@Entity
@Table(name = "application", schema = "obd")
public class TblApplication {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_id")
private Long applicationId;
@Column(name = "application_reference_number")
private String applicationReferenceNumber;
// Other fields...
@ManyToOne
@JoinColumn(name = "application_membership_id", referencedColumnName = "application_membership_id")
private TblApplicationMembership applicationMembershipByApplicationMembershipId;
}
@Getter
@Setter
@Entity
@Table(name = "application_membership", schema = "obd")
public class TblApplicationMembership {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_membership_id")
private Long applicationMembershipId;
@Column(name = "membership_reference_number")
private String membershipReferenceNumber;
// Other fields...
@OneToMany(mappedBy = "applicationMembershipByApplicationMembershipId", cascade = CascadeType.PERSIST)
@JsonManagedReference
private Collection<TblApplicationAddress> applicationAddressesByApplicationMembershipId;
}
@Getter
@Setter
@Entity
@Table(name = "application_address", schema = "obd")
public class TblApplicationAddress {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_address_id")
private Long applicationAddressId;
@Column(name = "address_type_code")
private String addressTypeCode;
@Column(name = "address_line1_number")
private String addressLine1Number;
// Other fields...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "application_membership_id", referencedColumnName = "application_membership_id")
@JsonBackReference
private TblApplicationMembership applicationMembershipByApplicationMembershipId;
}
服务层:
tblApplication = applicationDataService.save(tblApplication);
数据服务:
public T save(T t) throws DataServiceException {
try {
t = em.merge(t);
em.flush();
em.clear();
return t;
} catch (Exception ex) {
throw new DataServiceException("Error BaseDataService.save...", ex);
}
}
我已经尝试使用@JsonBackReference、@JsonManagedReference和cascade = CascadeType.PERSIST,正如这些讨论中所建议的:
不幸的是,这些方法并没有解决问题。如果我无法正常工作,我可能必须先手动保存父实体,然后在保存之前将外键 ID 分配给子实体,但由于复杂性和大小,我宁愿避免这种解决方法对象结构。
问题: 在持久化这些实体时,什么可能导致子表中的外键保持为空?是否有我可能丢失的配置或注释,或者是否有更好的方法来确保在保存父实体时正确设置外键?
我找不到我想要的分辨率,因此采用了更手动的方法。
首先,在父 JPA 类上将级联设置为 CascadeType.ALL 非常重要。
其次,@JsonManagedReference 和 @JsonBackReference 没有区别,所以我删除了注释。
以下是更新的 JPA 实体:
@Getter
@Setter
@Entity
@Table(name = "application", schema = "obd")
public class TblApplication {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_id")
private Long applicationId;
@Column(name = "application_reference_number")
private String applicationReferenceNumber;
// Other fields...
@ManyToOne
@JoinColumn(name = "application_membership_id", referencedColumnName = "application_membership_id", cascade = CascadeType.ALL)
private TblApplicationMembership applicationMembershipByApplicationMembershipId;
}
@Getter
@Setter
@Entity
@Table(name = "application_membership", schema = "obd")
public class TblApplicationMembership {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_membership_id")
private Long applicationMembershipId;
@Column(name = "membership_reference_number")
private String membershipReferenceNumber;
// Other fields...
@OneToMany(mappedBy = "applicationMembershipByApplicationMembershipId", cascade = CascadeType.ALL)
private Collection<TblApplicationAddress> applicationAddressesByApplicationMembershipId;
}
@Getter
@Setter
@Entity
@Table(name = "application_address", schema = "obd")
public class TblApplicationAddress {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_address_id")
private Long applicationAddressId;
@Column(name = "address_type_code")
private String addressTypeCode;
@Column(name = "address_line1_number")
private String addressLine1Number;
// Other fields...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "application_membership_id", referencedColumnName = "application_membership_id")
private TblApplicationMembership applicationMembershipByApplicationMembershipId;
}
这是我试图避免的服务层中的手动代码
tblApplication = applicationDataService.save(tblApplication);
Collection<TblApplicationAddress> addresses = tblApplicationMembership.getApplicationAddressesByApplicationMembershipId();
for (TblApplicationAddress entity : addresses) {
entity.setApplicationMembershipByApplicationMembershipId(tblApplicationMembership);
}
tblApplication = applicationDataService.save(tblApplication);
我确信有一种方法可以配置 JPA 类来避免这种手动解决方法,但如果有人发现自己面临时间压力,并且需要解决方案,这就可以了。