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

时间:2014-02-20 19:32:24

标签: java hibernate jpa spring-data 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,如果是,则用数据库中找到的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”不会持久存储到数据库中。

1 个答案:

答案 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中存储新实体,请删除级联选项。