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

我如何在不更新子实体的情况下持久化父实体,因为它们有多对多关系?

亢嘉茂
2023-03-14

我有一个父实体a,它与映射在a_B表和a_C表中的实体B和实体C有多对多关系。在持久化时,我希望只持久化a、a_B和a_C,而不持久化B和C。如果我不使用cascadetype。all i get“object references a unsaved transient instance-save the transient instances before flush”错误。如果我使用cascade。所有的表都会更新。

这是我的父母实体学生(getter和setter存在但未显示)

@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int studentId;
......
...... 
@ManyToMany()
@JoinTable(name = "student_preferredCountry",joinColumns = @JoinColumn(name 
= "studentId"),inverseJoinColumns = @JoinColumn(name = "countryId"))
private Set<Country> countries;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "student_preferred_course",joinColumns = @JoinColumn(name 
= "studentId"),inverseJoinColumns = @JoinColumn(name = "courseId"))
private Set<Course> courses;

这是我的孩子实体课程

@Entity
public class Course {
private String courseName;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int courseId;
@ManyToMany(mappedBy = "courses")
private List<Student> coursestudents;

这是我的另一个孩子实体国家

@Entity
public class Country {
@Id
private int countryId;
private String countryName;
@ManyToMany(mappedBy = "countries")
private List <Student> students;

这就是我坚持的方式

public boolean studententry(@RequestBody Student stud){
studentRepository.save(stud);

这是示例json请求

{

"studentFname": "fdfd",
"studentMname": "dfdf",
"studentLname": "fdf",
"studentFatherName": "fd",
"studentMotherName": "dfd",
"studentEmail": "dfd",
"studentAddress": "df",
"studentPhone": "df",
"countries": [
    {
        "countryId": "1",
        "countryName": "aus"
    },
    {
        "countryId": "2",
        "countryName": "newz"
    }
],
"courses": [
    {
        "course_id": "1",
        "course_name": "IELTS"
    },
    {
        "course_id": "2",
        "course_name": "TOEFL"
    }
    ]

}

基本上,我想添加所有的学生属性,student_curses,student_stcountry,而不需要坚持课程和国家表

共有2个答案

韩阳成
2023-03-14

您需要从@ManyToMany切换到@OneToMany

然后,您可以将级联放在< code>Student上,并在< code>StudentCourse和< code>StudentCountry实体中省略它。

唯一的缺点是需要为这些链接表创建中间实体:

学生

@OneToMany(cascade = CascadeType.ALL, mappedBy="student")
private Set<StudentCourse> courses;

选课表

@ManyToOne
private Student student;

@ManyToOne
private Course course;

课程

@Entity
public class Course {
private String courseName;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int courseId;
@ManyToMany(mappedBy = "courses")
private List<StudentCourse> coursestudents;

您需要相应地修改传入的json对象,以支持那些中间实体ofc。

孟洋
2023-03-14

首先,级联=ALL所做的与您想要的相反。ALL=PERSIST、MERGE、REFRESH、DETACH、REMOVE,所以它基本上说“每当我存储、更新或删除学生时,对所有相关的课程执行相同的操作”,等等。

对于@ManyToMany关联,PERSISTMERGEREMOVE 没有多大意义。您可能希望保留 REFRESHDETACH,但建议您摆脱其余部分。

其次,删除 MERGE 具有获取 TransientObjectException 的副作用。发生这种情况是因为您尝试保存引用其他分离实体的分离实体。您可能正在调用 repository.save(student),但这只会合并学生实体,并且引用的课程实体保持分离状态。

若要解决此问题,需要将分离的实体实例替换为具有相同 id 的托管实体实例:

Set<Courses> managedCourses = new HashSet<>();
for (Course course : stud.getCourses()) {
    managedCourses.add(courseRepository.getOne(course.getId()));
}
stud.setCourses(managedCourses);
studentRepository.save(stud); //no TransientObjectException this time!

(注意< code>getOne()在循环中的使用;您可能很想使用< code>findAllById(),认为这样性能会更好,但是< code>getOne()的好处是它不会从数据源获取相关的实体状态。< code>getOne()是由< code>JpaRepository提供的,特别考虑到这个用例:在实体之间建立关联)

最后,我可以看到stud@RequestBody注释,这表明我们在这里是一个Controller类。对于上述方法,您希望使用@Transactional将整个方法包装在事务中。由于事务控制器方法不是很好的实践,我建议将studentry方法的主体提取到单独的@transactional@Service注释bean中。

 类似资料:
  • 我是Spring/JPA/Hibernate的新手,虽然听起来很简单,但现实并非如此。我需要一些帮助。 第1轮,我创建一个新的父级和一个新的子级,将子级添加到父级列表中,并在子级上设置父级。我救了父母,孩子也就救了。 现在,第二轮,我添加一个新的孩子: 然而,这一次的新孩子却从来没有坚持过! 通过hibernate(痛苦!)来跟踪这个,我发现了以下内容: 第二次保存时,问题是第二个(新)子级。 问

  • 问题内容: 我们使用的是带有Hazelcast 3.6.1 2级缓存的Hibernate 3.5.6-Final。 情况 我和具有Hibernate设置的实体之间存在双向,一对多关系。实体类定义如下: 父级的Hibernate映射定义如下: 子项的hibernate映射定义如下: 现在,当前代码向中添加了,如下所示: 问题是第二行代码导致Hibernate加载 所有 子代。在我们的设置中,这是一个

  • 情况: 我有两个与OneTomany/ManyToone关系相关的实体。 想象一下,每个类也有一个名为id和getter和setter的PK。 问题: 如果我创建一个EntityA实例并设置一个与已经存在的EntityB实例的关系并持久化这个新实例,那么所有数据都会正确地保存到数据库中。但是,如果我从我的EntityManager请求EntityB的实例,它的列表中将不包含刚刚持久化的Entity

  • 尝试获取父实体(Msg)的实体,其中父PK (msg_id)是子实体中的FK时,尝试保持子实体(MsgRetry)时出错。 错误,如:org.hibernate.id.IdentifierGenerationException:试图从null一对一属性分配id 父实体,不需要知道子实体(至少我认为它不需要知道)。一旦子实体被持久化,我就会尝试也持久化父实体。我可以通过在子实体中没有父实体并调用关联

  • 为了理解为什么要持久化子实体,下面是映射。 我有作者(id,姓名,书籍)和书籍(id,标题,作者)实体。他们的关系是很多的,因为任何作者可能有多个书,任何书可能有多个作者。此外,我有BookClient(id,名称,rentDate,books) - 与Book实体的关系是OneToMany,因为任何客户都可以向许多书籍租用零。 Author.java Book.java BookClient.j

  • 对于新学生和新课程的情况,它工作得很好,但是在新课程和现有学生的情况下,我会从数据库中抛出一个唯一的约束冲突。关系类似于下面。 在持久化之前,我尝试使用entitymanager查找一个学生,如果该学生存在,则使用该实例而不是新的学生实例。这也不起作用,它仍然尝试执行插入而不是更新