我有两个主要实体:Client
和Bundle
。它们具有双向ManyToMany关系,可以按预期工作。例子:
Set<Bundle>
中删除了一个包。同一个捆绑包将更新其Set<Client>
客户端。捆绑实体将保留。所有这些都是双向的。
Client
和Bundle
都具有OneToMany关系,作为复合键,具有实体ClientBundleApproval
。它还有一个枚举(批准,拒绝,待定)。
我的问题是:假设我配置了多个实体。客户有几个捆绑包,有几个批准待定。当我尝试删除客户端时,如果在ClientBundleApproval
中存在包含复合键的行,将不会删除 。
我的预期结果是,ClientBundleApproval
中包含该客户端ID的所有行都将被删除,并且所有捆绑包都会删除其相关批准的集合,并更新客户端(基本上是级联删除,但仅限于复合键表而不是其他实体)。添加级联删除会导致删除客户端以删除复合键,还会删除捆绑包(这不是所需行为)。
我需要帮助弄清楚我的配置是否有问题,或者是不可能的。我假设我可能首先删除复合键行,但我需要保持处理这些实体的服务逻辑分开。 (例如,在ClientService
中不必注入其他实体&#39; JpaRepository<T, ID>
)
实施说明:我正在使用Spring JPA,因此对于每个实体我都有一个扩展Spring JpaRepository<T, ID>
的接口,我将其注入服务类并使用它进行CRUD操作而不是EntityManager
。
我尝试从OneToMany中移除mappedBy,不同类型的级联(在关系声明和使用@Cascade
中),有和没有孤儿删除。没有什么我能想到的。
实体和图表:
客户(我删除了一些样板)
@Entity
@Table(name = "client_details")
public class Client implements Serializable {
@JoinTable(
name = "client_bundle",
joinColumns = { @JoinColumn(name = "client_id") },
inverseJoinColumns = { @JoinColumn(name = "bundleName") }
)
@Column(name = "bundles")
@ManyToMany(fetch = FetchType.EAGER /* all types of cascade except delete */)
private Set<Bundle> clientBundles;
@OneToMany(mappedBy = "client", fetch = FetchType.EAGER, orphanRemoval = true /* all types of cascade except delete */)
private List<ClientBundleApproval> approvals;
}
捆绑
@Entity
@Table(name = "bundle")
public class Bundle implements Serializable {
@ManyToMany(mappedBy="clientBundles", fetch = FetchType.EAGER /* all types of cascade except delete */)
private Set<Client> clients;
@OneToMany(mappedBy = "bundle", fetch = FetchType.EAGER, orphanRemoval = true /* all types of cascade except delete */)
private List<ClientBundleApproval> approvals;
}
ClientBundleApproval
@Entity
@Table(name = "client_bundle_approval")
public class ClientBundleApproval implements Serializable {
@EmbeddedId
private ClientBundleKey clientBundleKey;
@ManyToOne(fetch = FetchType.EAGER /* all types of cascade except delete */)
@JoinColumn(name = "client", referencedColumnName = "id")
@MapsId("clientId")
private Client client;
@ManyToOne(fetch = FetchType.EAGER /* all types of cascade except delete */)
@JoinColumn(name = "bundle", referencedColumnName = "id")
@MapsId("bundleId")
private Bundle bundle;
@Enumerated(EnumType.STRING)
private ClientBundleApprovalStatus approvalStatus;
}
ClientBundleKey
@Embeddable
public class ClientBundleKey implements Serializable{
private String clientId;
private String bundleId;
}