我有以下实体
@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,如果是,则用数据库中找到的A替换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上使用evict(),但是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”,但我认为对象“unwantedB”不会持久存储到数据库中。
答案 0 :(得分:1)
为什么Spring-Data会保存这个未引用的B对象。?
因为您在收集关联中使用cascade = { CascadeType.MERGE, CascadeType.PERSIST })
如果我直接使用Hibernate,我可以使用evict() 像这样不需要的B,但是Spring-Data没有公开这样的调用
这是正确的,因此请考虑将关系中的B字段设置为null。这意味着删除从A到B的引用
a.setB( new B() );
到a.setB(null);
之前,如果不是实体,则会在持续时间内添加
如果您不想在B中存储新实体,请删除级联选项。