我有一个让你咆哮的奇怪问题。我有(也很奇怪)Spring / Hibernate应用程序,它旨在以下列方式管理数据库(我简化了一些事情,所以不要混淆源代码提到略有不同的表/列):
active_proxy_view table:
id | entity
<uuid> | <string containing json>
archive_proxy_view table:
id | entity
<uuid> | <string containing json>
track_reference table:
ref_type | ref_id | track_domain | track_type | track_id |
'proxy' | <uuid> | 'example.com' | 'customer' | '123' |
保留两个表是必需的 - 我需要同时拥有历史记录/统计查询和业务值查询,以便现在处于活动状态,因此我需要为活动代理保持紧密设置。 track_reference
表用于搜索,因此我可以执行以下查询:
SELECT p.id, p.entity FROM archive_proxy_view AS p
INNER JOIN track_reference AS t1 ON
t1.ref_id = p.id AND
t1.ref_type = 'proxy' AND
t1.track_domain = 'example.com' AND
t1.track_type = 'customer' AND
t1.track_id = '123'
INNER JOIN track_reference AS t2 ON
t2.ref_id = p.id AND
t2.ref_type = 'proxy' AND
t2.track_domain = 'example.com' AND
t2.track_type = 'campaign' AND
t2.track_id = 'halloween-2017'
(可能不是100%正确,我有一段时间没有原始的SQL经验)
这就是问题所在:
active_proxy_view
和archive_proxy_view
个实体都从一个在@OneToMany
实体上指定track_reference
关系的类继承; @ManyToOne
使用率实际上是不可能的,因为有很多实体与跟踪参考相关联track_reference
是单独管理的(这也是强制性的)track_reference
表分开管理视图,但每当我告诉Hibernate从active_proxy_view
表中删除实体时,它也会带走track_reference
个实体。即使我使用级联注释值,默认情况下为空(并且据我所知,这意味着不应该使用父级删除子记录)。但是,我有可能错过了一些东西。我也没有使用自定义@SQLDeleteAll
破解整个事情,我仍然可以在常规日志中看到常规删除:
55 Query delete from tracking_reference where referenced_entity_id='13c6b55c-f9b7-4de7-8bd4-958d487e461c' and referenced_entity_type='proxy' and tracked_entity_type='agent'
55 Query delete from tracking_reference where referenced_entity_id='13c6b55c-f9b7-4de7-8bd4-958d487e461c' and referenced_entity_type='proxy' and tracked_entity_type='lead'
55 Query delete from tracking_reference where referenced_entity_id='13c6b55c-f9b7-4de7-8bd4-958d487e461c' and referenced_entity_type='proxy' and tracked_entity_type='source'
53 Query DELETE FROM `tracking_reference` WHERE `referenced_entity_type` = 'proxy' AND referenced_entity_id = '13c6b55c-f9b7-4de7-8bd4-958d487e461c' AND 1 = 0
我正在使用Hibernate 5.2.3.Final通过Spring 4.3.2.RELEASE / Spring Data JPA 1.10.2.RELEASE
所以,问题是:如何在删除父级时阻止Hibernate删除关联实体?
实体的源代码如下所示:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class ProxyViewEntryTemplate {
@Id
@NotNull
@Column(nullable = false)
private String id;
@NotNull
@Column
private String entity;
// some other columns
@OneToMany
@JoinColumn(name = TrackRef.REFERENCE_ID_COLUMN_NAME) // 'reference_entity_id`
@Where(clause = ProxyView.TRACK_WHERE_JOIN_CLAUSE) // `referenced_entity_type` = 'proxy'
@SQLDeleteAll(sql = ProxyView.TRACK_DELETE_ALL_QUERY) // DELETE FROM `tracking_reference` WHERE `referenced_entity_type` = 'proxy' AND referenced_entity_id = ? AND 1 = 0
private Collection<TrackingReference> track = new ArrayList<>();
// setters, getters, hashCode, equals
}
@Entity
@Table(name = "active_proxy")
public class ActiveProxyViewEntry extends ProxyViewEntryTemplate {}
@Entity
@Table(name = "tracking_reference")
@IdClass(TrackingReferenceId.class)
public class TrackingReference {
@Id
@Column(name = "tracked_entity_type", nullable = false)
@NotNull
private String trackedType;
@Id
@Column(name = "tracked_entity_domain", nullable = false)
private String trackedDomain;
@Id
@Column(name = "tracked_entity_id", nullable = false)
private String trackedId;
@Id
@Column(name = "referenced_entity_type", nullable = false)
@NotNull
private String referencedType;
@Id
@Column(name = "referenced_entity_id", nullable = false)
@NotNull
private String referencedId;
// setters, getters, hashCode, equals
}
整个事情是通过Spring JPA Repositories管理的:
@NoRepositoryBean
public interface SuperRepository<E, ID extends Serializable> extends PagingAndSortingRepository<E, ID>,
JpaSpecificationExecutor<E> {
}
public interface ActiveProxyViewRepository extends SuperRepository<ActiveProxyViewEntry, String> {}
// the call for deletion
public CompletableFuture<Void> delete(ID id) {
...
descriptor.getRepository().delete(descriptor.getIdentifierConverter().convert(id));
...
}
// which is equal to
...
ActiveProxyViewRepository repository = descriptor.getRepository();
String uuidAsString = descriptor.getIdentifierConverter().convert(id);
repository.delete(uuidAsString);
...
答案 0 :(得分:0)
如果删除@JoinColumn
,则不应出现此问题。
如果需要保留@JoinColumn
,则需要删除持久性提供程序通过将注释更改为自动应用的外键约束要求:
@JoinColumn(
name = "yourName"
foreignKey = @Foreignkey(value = ConstraintMode.NO_CONSTRAINT)
)
然后,您应该能够删除视图实体,而不必强制删除跟踪引用。
答案 1 :(得分:0)
事实证明这是一个典型的拍摄自己的脚步场景。
跟踪引用以相当复杂的方式更新:
事实证明我的.equals
方法写错了,几乎在每种情况下都返回false。因此,通常每个引用都从数据库中删除(您可以在相关日志中看到的查询),所以这是我的错。
在我修复之后,只运行@SQLDeleteAll
查询 - 由于我不知道的原因,它仍然像是设置了cascade选项一样。我设法使用@OneToMany(updatable = false, insertable = false)
摆脱它;它似乎是一个肮脏的黑客,但我没有足够的时间来挖掘它。
我还没有彻底测试过,但是,我希望,这可以解决问题。