当前位置: 首页 > 知识库问答 >
问题:

Spring-Data-Jpa从子级到父级的级联

葛和志
2023-03-14

假设我有一个应用程序来处理一系列的书。

我的应用程序允许向库中添加新书。创建书籍时,用户可以在列表中选择作者,如果作者尚不存在,则可以将其添加到列表中,并在表单字段中提供其姓名。填写表单后,数据将发送到WS,类似

{ 
  "name" : "The Book name"
  "author" : {
     "name" : "author's name"
   }
}

然后我将json映射到我的实体中

书:

@Entity
@Table(name = "book")
public class Book{
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    private Author author;
}

作者

@Entity
@Table(name = "author")
public class Author{
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy = "author", cascade = { CascadeType.ALL })
    private List<Book> books;
}

这不会像用户尝试添加新作者一样工作,当我尝试. sav()时,我会收到错误:

组织。冬眠TransientPropertyValueException:对象引用未保存的瞬态实例

有没有办法用Spring数据Jpa来处理这种情况,或者我必须手动检查json中是否有作者id,如果没有,也就是说这是一个新作者,那么手动运行作者创建,然后保存新书?

谢谢!

共有1个答案

麻鹏鹍
2023-03-14

正如您所猜测的,正如Javadoc所说,必须级联到关联目标的级联操作”。但是,请确保您理解mapdBy定义了关系的拥有实体。拥有实体是实际执行持久化操作的实体,除非被级联设置覆盖。在这种情况下,儿童是拥有实体。

@Entity
public class Parent {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy="parent")
    private Set<Child> children;

当您创建子对象的集合,并将其设置到父对象中,然后保存父对象时,父对象上的级联设置就会起作用。然后,保存操作将从父级级联到子级。这是级联设置的更典型和预期用例。然而,它确实会导致数据库操作自动发生,这并不总是一件好事。

当孩子被持久化时,会在孩子身上发生Cascade设置,因此您可以在那里放置一个cascade注释,但继续阅读...

@Entity
public class Child {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(cascade=CascadeType.ALL)
    private Parent parent;

您将通过持久化子对象来持久化父对象和子对象。

tx.begin();
Parent p = new Parent();
Child c = new Child(); 
c.setParent(p);
em.persist(c);
tx.commit();

当您删除子项时,它将同时删除父项和子项。

tx.begin();
Child cFound = em.find(Child.class, 1L);
em.remove(cFound);
tx.commit();
em.clear();

这就是你的问题所在。如果你有一个以上的孩子会发生什么?

em.clear();
tx.begin();
p = new Parent();
Child c1 = new Child(); 
Child c2 = new Child(); 
c1.setParent(p);
c2.setParent(p);
em.persist(c1);
em.persist(c2);
tx.commit();

一切都很好,直到您删除其中一个子级

em.clear();
tx.begin();
cFound = em.find(Child.class, 2L);
em.remove(cFound);
tx.commit();

然后,当级联传播到父级但数据库中仍有第二个子级时,您将获得完整性约束违规。当然,您可以通过删除单个提交中的所有子级来解决它,但这变得有点混乱,不是吗?

从概念上讲,人们倾向于认为传播是从父传播到子传播的,因此如果不是这样的话,这是非常违反直觉的。此外,如果你不想仅仅因为书店出售了作者所有的书就删除他或她的书,那该怎么办?在这种情况下,您可能是混合级联,有时是从子级到父级,有时是从父级到子级。

一般来说,我认为数据库代码最好非常精确。阅读、理解和维护专门先保存父级然后保存子级的代码要比在其他地方添加注释容易得多,我可能知道也可能不知道这些注释正在隐式地执行其他数据库操作。

 类似资料:
  • 问题内容: 假设我们有3个Entities对象类: 如何使用JPA2.x(或hibernate)批注来: 父级删除时(一对多)自动删除所有子级 删除后自动从子级列表中删除子级(多对一) 儿童删除时(一对一)自动删除玩具 我正在使用Hibernate 4.3.5和mysql 5.1.30。 谢谢 问题答案: 如本文所述, 实体状态转换应从父级到子级联,而不是相反。 您需要这样的东西:

  • 问题内容: 我用这个文章为例(做出反应的方式),但它不是为我工作。请指出我的错误,因为我不明白怎么了。 这是我看到的错误: 未捕获的TypeError:this.props.onClick不是函数 这是我的代码: 提前致谢! 问题答案: 问题在于回调内部不引用React组件,因此是。 您可以通过将第二个参数传递给来显式设置值: 现在,回调 内部 的值与回调 外部 (即实例)的值相同。 这与Reac

  • 我有两个从抽象类继承的类,它们有父子关系。 所以我使用了注释OneToOne和ManyToOne,但是子类中的父实体总是为空。有人能帮我吗,我花了几个小时谷歌和测试了许多conf,但没有成功。 这些是我的类中的代码: ... ... ... 如果我不添加@JoinCol列注释,JPA会创建一个关联表,但无法检索父级,而关联可以直接通过在数据库中请求来完成。 非常感谢你的帮助。 祝好

  • 问题内容: 我有一个关于从子实体ir引用ParentEntities的问题,如果我有这样的事情: Parent.java: 和Child.java: 将创建以下表: 好的,到目前为止,一切都很好。但是,当涉及到使用Java的Reference时,我想,您可以做这样的事情。 这导致在数据库中: 但是事实并非如此,您必须明确地将“父级”设置为“子级”(我认为框架可能可以单独执行)。 因此,数据库中真正

  • 我有两个组成部分: 父组件 子组件 我试图从Parent调用child的方法,我尝试了这种方法,但无法得到结果: 有没有办法从父级调用子级的方法? 注意:子组件和父组件在两个不同的文件中。

  • 问题内容: 我有两个组成部分。 父组件 子组件 我试图从父级调用孩子的方法,我尝试过这种方法,但没有得到结果 有没有一种方法可以从父级调用子级的方法? 注意:子组件和父组件位于两个不同的文件中 问题答案: 首先,让我表示,这通常 不是 在React领域中解决问题的方法。通常,您要做的是将功能传递给道具中的子代,并传递事件中的子代的通知(或者更好的是:)。 但是,如果 必须 在子组件上公开命令式方法