Java 使用复合标识符@EmbeddedId和@OneToOne
我下面的例子是为了学习。目标是使用创建一些示例。不幸的是,我得到了一些奇怪的结果 实体:Java 使用复合标识符@EmbeddedId和@OneToOne,java,hibernate,spring-data-jpa,hibernate-cascade,Java,Hibernate,Spring Data Jpa,Hibernate Cascade,我下面的例子是为了学习。目标是使用创建一些示例。不幸的是,我得到了一些奇怪的结果 实体:课程,教师,课程知识 每门课程只能由一名教师讲授 我在班级老师和班级课程之间使用双向关系@OneToOne() 每个课程都包含一个复合主键。在我的示例中,我正在简化并使用只使用一个属性的复合主键 我的示例的目标是在课程对象被持久化时持久化关联的教师 id | first_name |last_name 1 | Jeff | Boss 老师班级: @Entity(name = "Teach
课程
,教师
,课程知识
每门课程只能由一名教师讲授
我在班级老师和班级课程之间使用双向关系@OneToOne()
每个课程都包含一个复合主键。在我的示例中,我正在简化并使用只使用一个属性的复合主键
我的示例的目标是在课程对象被持久化时持久化关联的教师
id | first_name |last_name
1 | Jeff | Boss
老师
班级:
@Entity(name = "Teacher")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "firstName")
private String firstName;
@Column(name = "lastName")
private String lastName;
@OneToOne(mappedBy = "officialTeacher")
private Course course;
//setter getter constructors are omitted for brevity
}
课程
课程:
@Entity(name = "Course")
public class Course {
@EmbeddedId
private CoursePk pkCourse;
@OneToOne(cascade = CascadeType.PERSIST)
private Teacher officialTeacher;
//setter getter constructors are omitted for brevity
}
应表示复合主键的CoursePk
@Embeddable
public class CoursePk implements Serializable {
@Column(name = "courseName")
private Integer courseId;
}
我的跑步示例:
private void composedPrimaryKey() {
Teacher teacher = new Teacher("Jeff", "Boss");
CoursePk composedPK = new CoursePk(1);
Course course = new Course(composedPK, teacher);
Course savedCourse = courseRepository.save(course);
}
因此,我的桌子看起来像:
课程表
course_name | official_teacher_id
1 | 1
id | first_name |last_name
1 | null | null
教师表
course_name | official_teacher_id
1 | 1
id | first_name |last_name
1 | null | null
如您所见,教师的信息不会持久化,而只保留id字段
神奇的是,当我将级联类型更改为CascadeType.ALL
时,所有内容都被持久化了
id | first_name |last_name
1 | Jeff | Boss
有人能解释一下为什么它不能只使用级联类型。PERSIST
我曾经遇到过这种情况。我甚至注意到更改为CascadeType.MERGE也可以工作。我对此进行了搜索,发现PERSIST假设已经创建了Teacher对象,它只是将teacherID分配给了Course对象。持久化意味着只将教师引用放在课程对象中。您还可以看到,它提供了课程对象不应更新教师对象的功能。教师对象应单独更新
更改为合并更新引用和教师对象。
CascadeType.ALL由于合并而起作用。Spring数据JPA:crudepository.save(…)
方法行为
考虑到使用了Spring数据JPA,有一些关于crudepository.save(…)
方法如何检测要执行的方法调用的细节:要么EntityManager.persist(…)
要么EntityManager.merge(…)
:
5.2.1. 拯救实体
可以使用crudepository.save(…)
方法保存实体。它使用底层JPAEntityManager
持久化或合并给定实体。如果实体尚未持久化,Spring Data JPA将通过调用entityManager.persist(…)
方法保存实体。否则,它将调用entityManager.merge(…)
方法
实体状态检测策略
Spring Data JPA提供以下策略来检测实体是否为新实体:
- Id属性检查(默认值):默认情况下,Spring数据JPA检查给定实体的标识符属性。如果identifier属性为null,则假定该实体是新的。否则,它被认为不是新的
-
回到问题上来
回到问题中提到的代码块。
由于课程
实例的标识符属性(主键)不为null,Spring Data JPA将其视为一个现有(非新)实体,并调用EntityManager.merge(…)
方法,而不是EntityManager.persist(…)
方法
其他参考资料
此外,请参考相关问题:。谢谢您的明确回答。关于将Spring数据Jpa与hibernate结合使用,我面临一些困惑。是否必须显式使用Entitmanager?或者spring数据存储库就足够了?如果您有一些关于两者使用的良好实践的参考资料,这将非常有帮助。>是否必须明确使用Entitmanager?或者spring数据存储库就足够了?大致上,Spring数据JPA存储库比JPA实体管理器更高级抽象。同时,如果可能的话,请考虑使用更高级的抽象——Spring数据JPA存储库。请参考以下问题:。@zakzak,顺便问一下,您是否确定教师
可能只有一门课程
:@OneToOne(mappedBy=“officialTeacher”)私人课程代码>?在我看来,一个老师可能有很多课程(0..*
)。我只是在尝试这两个实体之间可能存在的不同联系。在另一个例子中,我有一个老师可以教授很多课程。。。。。。