Java 无法保留具有OneToMany关系的子实体

Java 无法保留具有OneToMany关系的子实体,java,hibernate,jpa,integration-testing,one-to-many,Java,Hibernate,Jpa,Integration Testing,One To Many,我想为存储库方法创建一个集成测试,该测试将在两个日期之间找到培训师的培训,以便在下一步检查建议的培训日期是否与培训师时间表重叠 应用程序中的主要假设是,用户是主要实体,并从中创建相应的帐户、培训等。因此,用户是帐户和培训的活跃方 该方法如下所示: @Query( value = "SELECT t FROM Training t INNER JOIN t.trainingParticipants p " + "WHERE p.train

我想为存储库方法创建一个集成测试,该测试将在两个日期之间找到培训师的培训,以便在下一步检查建议的培训日期是否与培训师时间表重叠

应用程序中的主要假设是,用户是主要实体,并从中创建相应的帐户、培训等。因此,用户是帐户和培训的活跃方

该方法如下所示:

@Query(
      value =
          "SELECT t FROM Training t INNER JOIN t.trainingParticipants p "
              + "WHERE p.trainer.id = :trainer_id "
              + "AND t.trainingDate.startDate <= :trainingStartDate "
              + "AND t.trainingDate.endDate <= :trainingEndDate ")
  List<Training> findTrainingOfTrainer(
      @Param("trainer_id") Long trainerId,
      @Param("trainingStartDate") LocalDateTime trainingStartDate,
      @Param("trainingEndDate") LocalDateTime trainingEndDate);
@Service
@Slf4j
@Transactional
class TrainingService {

  private final TrainingRepository trainingRepository;
  private final UserRepository userRepository;

  public TrainingService(TrainingRepository trainingRepository, UserRepository userRepository) {
    this.trainingRepository = trainingRepository;
    this.userRepository = userRepository;
  }

  public List<Training> findTrainingBetweenTwoDatesQuery(
      Long trainerId, LocalDateTime startDate, LocalDateTime endDate) {
    return trainingRepository.findTrainingOfTrainer(trainerId, startDate, endDate);
  }
}
Training.java类看起来像:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
@SuperBuilder
public class Training extends AbstractBaseEntity {

  @Id
  @GeneratedValue
  private Long id;

  @Column(name = "training_start_date")
  LocalDateTime trainingStartDate;

  @Column(name = "training_end_date")
  LocalDateTime trainingEndDate;

  @OneToMany(mappedBy = "training", cascade = CascadeType.ALL)
  List<Exercise> exercises = new ArrayList<>();

  @Column(name = "difficulty_level")
  @Enumerated(EnumType.STRING)
  private DifficultyLevel difficultyLevel;

  @Column(name = "completed")
  boolean completed;

  @OneToOne(cascade = CascadeType.PERSIST)
  @JoinColumn(name = "training_participants_id", unique = true)
  private TrainingParticipants trainingParticipants;

  @Embedded private TrainingDate trainingDate;

  @ManyToOne(cascade = CascadeType.PERSIST)
  private User user;

}
@SpringBootTest
@ExtendWith(SpringExtension.class)
class TrainingServiceTest {

  @Autowired private TrainingRepository trainingRepository;

  @Autowired private UserRepository userRepository;

  @Autowired private AccountRepository accountRepository;

  @Autowired private TrainingService trainingService;

  @BeforeEach
  void setUp() {
    trainingService = new TrainingService(trainingRepository, userRepository);
  }

  @Test
  void shouldReturnTrainerTrainingBetweenTwoDates() {
    LocalDateTime now = LocalDateTime.now();

    userRepository.saveAll(userWithTrainingDataStub());

    List<Training> trainingOfTrainer =
        trainingRepository.findTrainingOfTrainer(1L, now.minusDays(7), now.plusDays(7));

    assertEquals(4, userRepository.findAll().size());
    assertEquals(4, trainingRepository.findAll().size());
    assertEquals(2, trainingOfTrainer.size());
  }

  List<User> userWithTrainingDataStub() {

    User user4 = userRepository.saveAndFlush(
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINER)
            .build());

    return List.of(
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINEE)
            .training(
                newHashSet(
                    Training.builder()
                        .trainingParticipants(
                            TrainingParticipants.builder()
                                .trainer(user4)
                                .build())
                        .trainingDate(
                            TrainingDate.builder()
                                .startDate(LocalDateTime.now().minusDays(3))
                                .endDate(LocalDateTime.now().minusDays(2))
                                .build())
                        .build()))
            .build(),
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINEE)
            .training(
                newHashSet(
                    Training.builder()
                        .trainingParticipants(
                            TrainingParticipants.builder()
                                .trainer(user4)
                                .build())
                        .trainingDate(
                            TrainingDate.builder()
                                .startDate(LocalDateTime.now().minusDays(5))
                                .endDate(LocalDateTime.now().minusDays(3))
                                .build())
                        .build()))
            .build(),
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINEE)
            .training(
                newHashSet(
                    Training.builder()
                        .trainingParticipants(
                            TrainingParticipants.builder()
                                .trainer(user4)
                                .build())
                        .trainingDate(
                            TrainingDate.builder()
                                .startDate(LocalDateTime.now().minusDays(5))
                                .endDate(LocalDateTime.now().minusDays(3))
                                .build())
                        .build()))
            .build());

  }


}
@allargsconstuctor
@诺尔格构装师
@吸气剂
@塞特
@实体
@超级建筑商
公共课堂培训扩展了AbstractBaseEntity{
@身份证
@生成值
私人长id;
@列(name=“培训开始日期”)
LocalDateTime培训开始日期;
@列(name=“培训结束日期”)
LocalDateTime TrainingEndate;
@OneToMany(mappedBy=“training”,cascade=CascadeType.ALL)
列表练习=新建ArrayList();
@列(name=“难度等级”)
@枚举(EnumType.STRING)
私人困难程度困难程度;
@列(name=“completed”)
布尔完成;
@OneTONE(cascade=CascadeType.PERSIST)
@JoinColumn(name=“training\u participants\u id”,unique=true)
私人培训参与者培训参与者;
@嵌入式私人培训日期培训日期;
@manytone(cascade=CascadeType.PERSIST)
私人用户;
}
我的测试类看起来像:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
@SuperBuilder
public class Training extends AbstractBaseEntity {

  @Id
  @GeneratedValue
  private Long id;

  @Column(name = "training_start_date")
  LocalDateTime trainingStartDate;

  @Column(name = "training_end_date")
  LocalDateTime trainingEndDate;

  @OneToMany(mappedBy = "training", cascade = CascadeType.ALL)
  List<Exercise> exercises = new ArrayList<>();

  @Column(name = "difficulty_level")
  @Enumerated(EnumType.STRING)
  private DifficultyLevel difficultyLevel;

  @Column(name = "completed")
  boolean completed;

  @OneToOne(cascade = CascadeType.PERSIST)
  @JoinColumn(name = "training_participants_id", unique = true)
  private TrainingParticipants trainingParticipants;

  @Embedded private TrainingDate trainingDate;

  @ManyToOne(cascade = CascadeType.PERSIST)
  private User user;

}
@SpringBootTest
@ExtendWith(SpringExtension.class)
class TrainingServiceTest {

  @Autowired private TrainingRepository trainingRepository;

  @Autowired private UserRepository userRepository;

  @Autowired private AccountRepository accountRepository;

  @Autowired private TrainingService trainingService;

  @BeforeEach
  void setUp() {
    trainingService = new TrainingService(trainingRepository, userRepository);
  }

  @Test
  void shouldReturnTrainerTrainingBetweenTwoDates() {
    LocalDateTime now = LocalDateTime.now();

    userRepository.saveAll(userWithTrainingDataStub());

    List<Training> trainingOfTrainer =
        trainingRepository.findTrainingOfTrainer(1L, now.minusDays(7), now.plusDays(7));

    assertEquals(4, userRepository.findAll().size());
    assertEquals(4, trainingRepository.findAll().size());
    assertEquals(2, trainingOfTrainer.size());
  }

  List<User> userWithTrainingDataStub() {

    User user4 = userRepository.saveAndFlush(
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINER)
            .build());

    return List.of(
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINEE)
            .training(
                newHashSet(
                    Training.builder()
                        .trainingParticipants(
                            TrainingParticipants.builder()
                                .trainer(user4)
                                .build())
                        .trainingDate(
                            TrainingDate.builder()
                                .startDate(LocalDateTime.now().minusDays(3))
                                .endDate(LocalDateTime.now().minusDays(2))
                                .build())
                        .build()))
            .build(),
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINEE)
            .training(
                newHashSet(
                    Training.builder()
                        .trainingParticipants(
                            TrainingParticipants.builder()
                                .trainer(user4)
                                .build())
                        .trainingDate(
                            TrainingDate.builder()
                                .startDate(LocalDateTime.now().minusDays(5))
                                .endDate(LocalDateTime.now().minusDays(3))
                                .build())
                        .build()))
            .build(),
        User.builder()
            .account(Account.builder().build())
            .userType(UserType.TRAINEE)
            .training(
                newHashSet(
                    Training.builder()
                        .trainingParticipants(
                            TrainingParticipants.builder()
                                .trainer(user4)
                                .build())
                        .trainingDate(
                            TrainingDate.builder()
                                .startDate(LocalDateTime.now().minusDays(5))
                                .endDate(LocalDateTime.now().minusDays(3))
                                .build())
                        .build()))
            .build());

  }


}
@SpringBootTest
@ExtendWith(SpringExtension.class)
班级培训服务测试{
@自动连线私人培训库培训库;
@自动连线专用用户存储库用户存储库;
@自动连线私人帐户存储库;
@自连线私人培训服务培训服务;
@之前
无效设置(){
trainingService=新的trainingService(trainingRepository,userRepository);
}
@试验
void应返回两个日期之间的TrainerTraining(){
LocalDateTime now=LocalDateTime.now();
saveAll(userWithTrainingDataStub());
列出培训计划=
trainingRepository.findTrainingOfTrainer(1L,现在。天数减少(7),现在。天数增加(7));
assertEquals(4,userRepository.findAll().size());
assertEquals(4,trainingRepository.findAll().size());
assertEquals(2,培训Trainer.size());
}
使用TrainingDataStub()列出用户{
用户user4=userRepository.saveAndFlush(
User.builder()
.account(account.builder().build())
.userType(userType.TRAINER)
.build());
返回列表(
User.builder()
.account(account.builder().build())
.userType(userType.培训生)
.培训(
新哈希集(
培训.建筑商()
.培训参与者(
TrainingParticipants.builder()
.培训师(用户4)
.build())
.培训日期(
TrainingDate.builder()
.startDate(LocalDateTime.now().minusDays(3))
.endDate(LocalDateTime.now().minusDays(2))
.build())
.build())
.build(),
User.builder()
.account(account.builder().build())
.userType(userType.培训生)
.培训(
新哈希集(
培训.建筑商()
.培训参与者(
TrainingParticipants.builder()
.培训师(用户4)
.build())
.培训日期(
TrainingDate.builder()
.startDate(LocalDateTime.now().minusDays(5))
.endDate(LocalDateTime.now().minusDays(3))
.build())
.build())
.build(),
User.builder()
.account(account.builder().build())
.userType(userType.培训生)
.培训(
新哈希集(
培训.建筑商()
.培训参与者(
TrainingParticipants.builder()
.培训师(用户4)
.build())
.培训日期(
TrainingDate.builder()
.startDate(LocalDateTime.now().minusDays(5))
.endDate(LocalDateTime.now().minusDays(3))
.build())
.build())
.build());
}
}
问题是第一个断言通过了,我可以保存4个用户,但第二个断言:
assertEquals(4,trainingRepository.findAll().size())

创建用户时失败且未保存我的培训。我只想在创建用户的同时保存我的培训。我很确定映射用户培训存在问题,但老实说,我没有看到任何其他可能的解决方案来达到理想的目标。我将非常感谢关于如何修复我的映射的建议,并在创建用户时能够坚持进行培训

您在OneToMany关联上没有cascade=PERSIST,因此坚持用户不会坚持用户的培训。@jbnize非常感谢您的回答。在@OneToMany端添加persist后,我收到一个异常:
org.springframework.dao.InvalidDataAccessApiUsageException:传递给persist的分离实体:com.appapplication.common.User;嵌套异常为org.hibernate.PersistentObjectException:传递给persist:com.appapplication.common.User的分离实体