我有一个引用Doctor和Patient id的MedicalNote,并且有一个date属性,所有这些都构成了MedicalNote的主键。MedicalNote和Doctor和Patient都有一对多的双向关系。我想确定这是否是在Hibernate中实现的正确方法。
医疗笔记
package com.example.doctorkom.Entities;
import jakarta.persistence.*;
import lombok.*;
import java.sql.Date;
@Entity
@Table(name = "MedicalNote")
@IdClass(MedicalNoteId.class)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MedicalNote {
@Column(name = "Diagnosis")
private String diagnosis;
@Column(name = "Investigations")
private String investigations;
@Column(name = "Prescription")
private String prescription;
@Id
@Column(name = "Date")
private Date date;
@Id
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
@JoinColumn(name = "PatientId")
private Patient patient;
@Id
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
@JoinColumn(name = "DoctorId")
private Doctor doctor;
}
字符串
MedicalNoteId
package com.example.doctorkom.Entities;
import lombok.*;
import java.io.Serializable;
import java.sql.Date;
@Getter
@Setter
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class MedicalNoteId implements Serializable {
private Patient patient;
private Doctor doctor;
private Date date;
}
型
医生
package com.example.doctorkom.Entities;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
@Table(name = "Doctor")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Doctor {
@Id
@Column(name = "UserId")
private Integer id;
@Column(name = "Title")
@Enumerated(EnumType.STRING)
private DoctorTitle title;
@Column(name = "Specialty")
@Enumerated(EnumType.STRING)
private DoctorSpecialty specialty;
@MapsId
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "UserId")
private SystemUser systemUser;
@OneToMany(mappedBy = "doctor", cascade = CascadeType.ALL, orphanRemoval = true)
@ToString.Exclude
private List<MedicalNote> medicalNotes;
@OneToMany(mappedBy = "doctor", cascade = CascadeType.ALL, orphanRemoval = true)
@ToString.Exclude
private List<TimeSlot> timeSlots;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
@JoinTable(
name = "WorksFor",
joinColumns = @JoinColumn(name = "DoctorId"),
inverseJoinColumns = @JoinColumn(name = "ClinicId")
)
@ToString.Exclude
private List<Clinic> clinics;
public void addMedicalNote (MedicalNote medicalNote) {
if (medicalNotes == null) {
medicalNotes = new ArrayList<>();
}
medicalNotes.add(medicalNote);
medicalNote.setDoctor(this);
}
void deleteMedicalNote (MedicalNote medicalNote) {
if (medicalNotes != null) {
medicalNotes.remove(medicalNote);
medicalNote.setDoctor(null);
}
}
public void addTimeSlot (TimeSlot timeSlot) {
if (timeSlots == null) {
timeSlots = new ArrayList<>();
}
timeSlots.add(timeSlot);
timeSlot.setDoctor(this);
}
void deleteTimeSlot (TimeSlot timeSlot) {
if (timeSlots != null) {
timeSlots.remove(timeSlot);
timeSlot.setDoctor(null);
}
}
public void addClinic (Clinic clinic) {
if (clinics == null) {
clinics = new ArrayList<>();
}
clinics.add(clinic);
clinic.getDoctors().add(this);
}
void deleteClinic (Clinic clinic) {
if (clinics != null) {
clinics.remove(clinic);
clinic.getDoctors().remove(this);
}
}
}
型
患者
package com.example.doctorkom.Entities;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
@Table(name = "Patient")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Patient {
@Id
@Column(name = "UserId")
private Integer id;
@Column(name = "Occupation")
private String occupation;
@Column(name = "MaritalStatus")
private String maritalStatus;
@Column(name = "Insurance")
private String insurance;
@MapsId
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "UserId")
private SystemUser systemUser;
@OneToMany(mappedBy = "patient", cascade = CascadeType.ALL)
@ToString.Exclude
private List<MedicalNote> medicalNotes;
public void addMedicalNote (MedicalNote medicalNote) {
if (medicalNotes == null) {
medicalNotes = new ArrayList<>();
}
medicalNotes.add(medicalNote);
medicalNote.setPatient(this);
}
}
型
这种方法在用H2测试时会遇到一些麻烦,
@Test
void whenDeleteByDoctorId_thenDeleteMedicalNote() {
// Given
Account patientAccount = Account.builder().
email("[email protected]").
username("JohnSmith1").
password("JohnyJohny123").
role(Role.PATIENT).
build();
SystemUser patientSystemUser = SystemUser.builder().
firstName("John").
lastName("Smith").
birthdate(Date.valueOf("1985-11-14")).
gender(Gender.MALE).
address("221B Baker Street").
mobilePhone("(555) 555-5555").
landlinePhone("(555) 123-4567").
account(patientAccount).
build();
Patient patient = Patient.builder().
occupation("Engineer").
maritalStatus("Single").
insurance("BOBA").
systemUser(patientSystemUser).
build();
patientRepository.save(patient);
Account doctorAccount = Account.builder().
email("[email protected]").
username("DrSmith1").
password("Medical123").
role(Role.DOCTOR).
build();
SystemUser doctorSystemUser = SystemUser.builder().
firstName("Smith").
lastName("Health").
birthdate(Date.valueOf("1976-10-30")).
gender(Gender.MALE).
address("123 Main Street").
mobilePhone("(666) 666-6666").
landlinePhone("(555) 765-4321").
account(doctorAccount).
build();
Doctor doctor = Doctor.builder().
title(DoctorTitle.PROFESSOR).
specialty(DoctorSpecialty.ONCOLOGIST).
systemUser(doctorSystemUser).
build();
doctorRepository.save(doctor);
MedicalNote medicalNote = MedicalNote.builder().
date(Date.valueOf("2023-04-01")).
patient(patient).
doctor(doctor).
build();
medicalNoteRepository.save(medicalNote);
patient.addMedicalNote(medicalNote);
doctor.addMedicalNote(medicalNote);
patientRepository.save(patient);
doctorRepository.save(doctor);
// When
medicalNoteRepository.deleteByDoctorId(doctor.getId());
// Then
assertTrue(medicalNoteRepository.findByDoctorId(doctor.getId()).isEmpty());
}
型
抛出当前异常
Hibernate: insert into Account (Email,Enabled,Password,Role,Username,Id) values (?,?,?,?,?,default)
Hibernate: insert into SystemUser (Address,Birthdate,FirstName,Gender,LandlinePhone,LastName,MobilePhone,AccountId) values (?,?,?,?,?,?,?,?)
Hibernate: insert into Patient (Insurance,MaritalStatus,Occupation,UserId) values (?,?,?,?)
Hibernate: insert into Account (Email,Enabled,Password,Role,Username,Id) values (?,?,?,?,?,default)
Hibernate: select
m1_0.Date,m1_0.DoctorId,d1_0.UserId,d1_0.Specialty,s1_0.AccountId,a1_0.Id,a1_0.Email,a1_0.Enabled,a1_0.Password,a1_0.Role,a1_0.Username,s1_0.Address,s1_0.Birthdate,s1_0.FirstName,s1_0.Gender,s1_0.LandlinePhone,s1_0.LastName,s1_0.MobilePhone,d1_0.Title,c1_0.DoctorId,c1_1.ClinicId,c1_1.Address,a2_0.AccountId,a3_0.Id,a3_0.Email,a3_0.Enabled,a3_0.Password,a3_0.Role,a3_0.Username,c1_1.Email,c1_1.LandlinePhone,c1_1.MobilePhone,c1_1.Name,m1_0.PatientId,p1_0.UserId,p1_0.Insurance,p1_0.MaritalStatus,p1_0.Occupation,s2_0.AccountId,a4_0.Id,a4_0.Email,a4_0.Enabled,a4_0.Password,a4_0.Role,a4_0.Username,s2_0.Address,s2_0.Birthdate,s2_0.FirstName,s2_0.Gender,s2_0.LandlinePhone,s2_0.LastName,s2_0.MobilePhone,m1_0.Diagnosis,m1_0.Investigations,m1_0.Prescription from MedicalNote m1_0 join Doctor d1_0 on d1_0.UserId=m1_0.DoctorId left join SystemUser s1_0 on s1_0.AccountId=d1_0.UserId left join Account a1_0 on a1_0.Id=s1_0.AccountId left join (WorksFor c1_0 join Clinic c1_1 on c1_1.ClinicId=c1_0.ClinicId) on d1_0.UserId=c1_0.DoctorId left join ClinicAdmin a2_0 on a2_0.AccountId=c1_1.ClinicId left join Account a3_0 on a3_0.Id=a2_0.AccountId join Patient p1_0 on p1_0.UserId=m1_0.PatientId left join SystemUser s2_0 on s2_0.AccountId=p1_0.UserId left join Account a4_0 on a4_0.Id=s2_0.AccountId where (m1_0.Date,m1_0.DoctorId,m1_0.PatientId) in ((?,?,?))
Hibernate: insert into SystemUser (Address,Birthdate,FirstName,Gender,LandlinePhone,LastName,MobilePhone,AccountId) values (?,?,?,?,?,?,?,?)
Hibernate: insert into Doctor (Specialty,Title,UserId) values (?,?,?)
Hibernate: insert into MedicalNote (Diagnosis,Investigations,Prescription,Date,DoctorId,PatientId) values (?,?,?,?,?,?)
Hibernate: select m1_0.Date,m1_0.DoctorId,m1_0.PatientId,m1_0.Diagnosis,m1_0.Investigations,m1_0.Prescription from MedicalNote m1_0 where m1_0.DoctorId=?
org.opentest4j.AssertionFailedError:
Expected :true
Actual :false
型
1条答案
按热度按时间fcg9iug31#
据我所知,问题是您的测试在一个事务中运行,并且您为
Parent
和Doctor
medicalNotes
字段设置了cascade = CascadeType.ALL
。因此deleteByDoctorId
标记了MedicalNote
实体以进行删除,但在事务结束时,Hibernate再次从doctor或parent传播持久状态。如果您删除
cascade = CascadeType.ALL
或在“When”和“Then”的单独事务中运行“Given”测试块-测试将正确完成。