gpt4 book ai didi

java - 从父实体中删除时,Spring data JPA @PreRemove ConcurrentModificationException

转载 作者:行者123 更新时间:2023-12-02 09:57:45 25 4
gpt4 key购买 nike

我有一个参与者可以注册类(class)的案例。

基本上我有以下实体配置(省略了 getter 和 setter 以及其他无用的属性):

@Entity
@Table(name = "course")
public class Course {

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "course")
private Set<Registration> registrations;

}

@Entity
@Table(name = "participant")
public class Participant {

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "participant")
private Set<Registration> registrations;

}

@Entity
@Table(name = "registration")
public class Registration {

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "course_id")
private Course course;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "participant_id")
private Participant participant;

@PreRemove
private void removeRegistrationFromHolderEntities() {
course.getRegistrations().remove(this);
participant.getRegistrations().remove(this);
}

}

然后我可以从我的 View 模型中删除注册或类(class)(我还删除了不必要的东西):

@Command
public void deleteRegistration(Registration reg) {
registrationMgr.delete(reg);
}

@Command
public void deleteCourse(Course crs) {
courseMgr.delete(crs);
}

问题:

  • 如果我删除注册,我需要 @PreRemove函数,这样我就可以删除引用。如果没有这个,删除将被忽略(没有错误,只是被忽略)
  • 如果我删除类(class),我必须删除 @PreRemove功能否则我得到一个 ConcurrentModificationException (显然...)

我也无法删除 deleteRegistration 中的引用方法(而不是 @PreRemove ),因为参与者注册是延迟加载的(会引发 failed to lazily initialize a collection of role: ..., could not initialize proxy - no Session 异常)。

这里最好的方法是什么?

我将 Java 11Spring Boot 1.0.4(以及 spring-boot-starter-data-jpa)结合使用。

编辑:

管理器/存储库或以这种方式定义(与 registrationparticipant 相同),因此它应该是事务性的(我的主类上没有 @EnableTransactionManagement 但不应该需要它,因为我不需要不要使用存储库之外的事务):

@Transactional
@Component("courseMgr")
public class CourseManager {

@Autowired
CourseRepository courseRepository;

public void saveOrUpdate(Course course) {
courseRepository.save(course);
}

public void delete(Course course) {
courseRepository.delete(course);
}
}

public interface CourseRepository extends CrudRepository<Course, Long> {
...
}

编辑2:

我想我找到了一个非常简单的解决方案:

我已经删除了 @PreRemove方法从实体,然后而不是像这样删除 deleteRegistration 中的引用方法(我尝试过但导致 failed to lazily initialize a collection of role 异常):

@Command
public void deleteRegistration(Registration reg) {
reg.getCourse().getRegistrations().remove(reg);
reg.getParticipant.getRegistrations().remove(reg);
registrationMgr.delete(reg);
}

我只是将parents设置为null,我不在乎,因为它会被删除......

@Command
public void deleteRegistration(Registration reg) {
reg.setCourse(null);
reg.setParticipant(null);
registrationMgr.delete(reg);
}

所以现在我也可以删除类(class)而不触发 ConcurrentModificationException@PreRemove .

EDIT3:我的错,上面的解决方案没有删除注册(仍然没有错误,但没有任何反应)。我以这个结束,它终于起作用了:

@Command
public void deleteRegistration(Registration reg) {
// remove reference from course, else delete does nothing
Course c = getRegistration().getCourse();
c.getRegistrations().remove(getRegistration());
courseMgr.saveOrUpdate(c);

// delete registration from the database
registrationMgr.delete(reg);
}

无需删除参与者的引用...

最佳答案

您的存储库设置不正确。您需要一个用于注册的复合 PK,并且您需要了解双向映射实际上仅用于查询。此外,CourseParticipate 中的双向映射存在挑战,因为通过 Registration 实体的 ManyToOne 关系是 默认情况下,FetchType.EAGER。有了所有 cascadefetch 注释,您就要求 JPA 提供复杂的组合,而您似乎还没有将其全部解决。从基础知识开始,一定要打印您的 SQL 语句,如果您想尝试从 JPA 中获得更多技巧,请从那里开始。

@Entity
@Data
public class Course {
@Id
private Integer id;
private String name;
}

@Entity
@Data
public class Participant {
@Id
private Integer id;
private String name;
}

@Entity
@Data
public class Registration {
@EmbeddedId
private RegistrationPK id;

@ManyToOne
@MapsId("participant_id")
private Participant participant;

@ManyToOne
@MapsId("course_id")
private Course course;
}

@Embeddable
@Data
public class RegistrationPK implements Serializable {
private static final long serialVersionUID = 1L;
private Integer course_id;
private Integer participant_id;
}

是您的基本实体RegistrationRepository 需要额外的查询。

public interface RegistrationRepository extends JpaRepository<Registration, RegistrationPK> {
Set<Registration> findByCourse(Course c);
}

并在示例中使用所有这些:

@Override
public void run(String... args) throws Exception {
create();
Course c = courseRepo.getOne(1);
Set<Registration> rs = read(c);
System.out.println(rs);
deleteCourse(c);
}

private void create() {
Course c1 = new Course();
c1.setId(1);
c1.setName("c1");
courseRepo.save(c1);

Participant p1 = new Participant();
p1.setId(1);
p1.setName("p1");
participantRepo.save(p1);

Registration r1 = new Registration();
r1.setId(new RegistrationPK());
r1.setCourse(c1);
r1.setParticipant(p1);
registrationRepo.save(r1);
}

private Set<Registration> read(Course c) {
return registrationRepo.findByCourse(c);
}

private void deleteCourse(Course c) {
registrationRepo.deleteAll( registrationRepo.findByCourse(c) );
courseRepo.delete(c);
}

关于java - 从父实体中删除时,Spring data JPA @PreRemove ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55869659/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com