Spring Data JPA持久化未引用的实体



我有以下实体

@Entity
public class A {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// ... //
@ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
@JoinColumn(name = "B_ID", nullable = false)
private B b;
}
@Entity
public class B {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Lob
private BitSet bitSet;
// ... //
@OneToMany(mappedBy = "b", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
Set<A> as;
}

在我的代码中,我有以下序列,创建一个A并分配一个新的B,稍后在代码中,当服务类保存A时,服务会检查数据库中是否已经存在等效的B,如果存在,则用数据库中找到的B替换A的B。我知道这有点复杂,但我们不希望创建A的代码了解数据库,当然,实际的代码更复杂。

// Initialization code happens in one part
A a = new A();
a.setB( new B() );  // This new B get's saved even if it is replaced later!
// Later a service is used to save the new A
B repoB = bRepository.findOneByBitSet( a.getB().getBitSet() );
if (repoB != null) {
a.setB(repoB);  // Replace the temporary B
} // Otherwise we will keep the original B.
aRepository.save(a);

好的,现在问题来了。A的原始B被保存到数据库中,即使这个新B没有被任何对象引用。为什么Spring Data要保存这个未引用的B对象。

如果我直接使用Hibernate,我本可以像这样对不需要的B使用reject(),但Spring Data没有公开这样的调用:

// Later a service is used to save the new A
B repoB = bRepository.findOneByBitSet( a.getB().getBitSet() );
if (repoB != null) {
B unwantedB = a.getB();
a.setB(repoB);  // Replace the unwanted B
hibernate.evict(unwantedB);
} // Otherwise we will keep the original B.
aRepository.save(a);

该场景的一个更直接的例子是:

A a = new A();
B unwantedB = new B();
a.setB(unwantedB);
B b = newB();
a.setB(b);
repository.save(a);

对象"a"应该通过引用对象"b"来持久化,但我认为对象"unntedB"不会持久化到数据库中。

为什么Spring Data要保存这个未引用的B对象。?

因为您在集合关联上使用cascade = { CascadeType.MERGE, CascadeType.PERSIST })

如果我直接使用Hibernate,我可以使用一个驱逐()在不需要的B上这样做,但Spring Data没有公开这样的调用

这是正确的,所以考虑将关系中B的字段设置为null。这意味着删除从A到B 的引用

持续之前的a.setB( new B() );a.setB(null);如果不是,实体将被添加一个持续时间

如果您不想在B中存储新实体,请删除级联选项。

最新更新