简体   繁体   English

Spring JPA 存储库删除方法不起作用

[英]Spring JPA repository delete method doesn't work

I can't get Spring JPA to delete bar entity with jpa repository delete method.我无法让 Spring JPA 使用 jpa 存储库删除方法删除 bar 实体。
Can anyone see where the problem is?谁能看出问题出在哪里?

doesn't work:不起作用:

barRepository.delete(bar.id);

Jpa repository: Jpa 存储库:

public interface BarRepository extends JpaRepository<Bar, Integer>

Hibernate entity mappings (only relevant parts): Hibernate 实体映射(仅相关部分):

@Entity(name = "foo")

@OneToMany(fetch = FetchType.EAGER, mappedBy = "foo", cascade = CascadeType.ALL, orphanRemoval = true)
@Fetch(FetchMode.SELECT)
private List<Bar> bars = new ArrayList<>();

@Entity(name = "bar")

@ManyToOne(optional = false)
@JoinColumn(name = "foo_id")
@Fetch(FetchMode.SELECT)
private Foo      foo;

EDIT : git repo with minimal reproducible example.编辑:git repo,带有最小的可重现示例。 HibernateDeleteApplicationTests.java contains test case. HibernateDeleteApplicationTests.java包含测试用例。

https://github.com/matijaivanus/hibernate-delete-problem https://github.com/matijaivanus/hibernate-delete-problem

The "problem" is your mapping. “问题”是您的映射。 Your collection is retrieved eagerly.您的收藏被急切地检索。 Now why would that be an issue.现在为什么这会是一个问题。 The deleteById in Spring Data JPA first does a findById which in your case loads the Bar and the Foo and eagerly the collection inside Foo . Spring 数据 JPA 中的deleteById首先执行findById在您的情况下加载BarFoo并急切地收集Foo中的集合。

Now the Bar is attempted to be deleted but due to it being still attached and referenced by another entity it would be persisted again, hence the delete is cancelled.现在试图删除Bar ,但由于它仍然被另一个实体附加和引用,它将再次被持久化,因此删除被取消。

To solve you have 3 options要解决你有3个选项

  1. Delete using a query and write your own query method for this使用查询删除并为此编写自己的查询方法
  2. Properly remove the Bar from Foo , set the relation to null and then persist Foo or delete Bar .Foo中正确删除Bar ,将关系设置为null ,然后保留Foo或删除Bar
  3. Mark either side of the assocation lazy (this still can fail due to 1).将关联的任一侧标记为惰性(由于 1,这仍然可能失败)。

Either of these will work.这些中的任何一个都可以。 The first one because it bypasses the JPA caching mechanisms, the second because now the association has been cut.第一个是因为它绕过了 JPA 缓存机制,第二个是因为现在关联已被切断。 The third can work but if the objects have already been loaded run into the same issue as 1.第三个可以工作,但如果对象已经加载,则会遇到与 1 相同的问题。

What if you use如果你使用

barRepository.delete(bar);

or或者

barRepository.deleteById(bar.id);

I can see that you try to pass bar.id as a parameter of delete method but it should be entity: void delete(T entity)我可以看到您尝试将bar.id作为delete方法的参数传递,但它应该是 entity: void delete(T entity)

[EDIT] [编辑]

It happens because you have bidirectional relationship and you need to update both sides of the relationship if two sides are persisted - attached to the current session发生这种情况是因为您有双向关系,如果双方保持不变,则需要更新关系的双方 - 附加到当前 session

How to fix it?如何解决?

You can add @PreRemoved annotaded method to the Bar class to synchronize both sides just before Bar is removed:您可以将@PreRemoved注释方法添加到Bar class 以在删除Bar之前同步两侧:

@PreRemove
public void preRemove() {
    this.foo.getBars().clear(); //of course this is just an example and probably you should have more complicated logic here
    this.foo = null;
}

Second solution is to create @Transactional method to save Foo and Bar is a separate transaction:第二种解决方案是创建@Transactional方法来保存FooBar是一个单独的事务:

@Service
public class FooService {

    @Transactional
    public Foo save() {
        Foo foo = new Foo();
        foo.setTitle("aaa");

        Bar bar = new Bar();
        bar.setName("fas");
        bar.setFoo(foo);

        foo.getBars().add(bar);

        return fooRepository.save(foo);
    }
} 

And now use it to save your entities现在用它来保存你的实体

@BeforeEach
public void before() {      
    this.foo = fooRepository.save(foo);
}

U can try using: barRepository.deleteById(bar.id)你可以尝试使用: barRepository.deleteById(bar.id)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM