首页 > 解决方案 > 在为嵌套对象创建自定义 Spring Data JPA 查询时获取 IllegalArgumentException

问题描述

我想创建一个自定义 Spring Data 查询,它将查找两个日期之间培训师的所有培训。

培训班长这样:

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

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

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

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

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

  @OneToOne(targetEntity = Training.class, fetch = FetchType.LAZY)
  private TrainingParticipants trainingParticipants;

  @OneToOne(targetEntity = Training.class, fetch = FetchType.LAZY)
  private TrainingDate trainingDate;
}

嵌套类如:

@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TrainingParticipants {

  @Id
  @GeneratedValue
  private Long id;

  @OneToOne(targetEntity = TrainingParticipants.class)
  private User trainer;

  @ElementCollection(targetClass = TrainingParticipants.class)
  private Set<User> trainee;
}

@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
class TrainingDate {

  @Id
  @GeneratedValue
  private Long id;

  private LocalDateTime startDate;

  private LocalDateTime endDate;
}

HashCodeEquals 合约和 @Version 用法的 AbstractBaseEntity 如下所示:

@ToString
@MappedSuperclass
@Getter
@SuperBuilder
public abstract class AbstractBaseEntity {

  @Version
  protected long version = 0;

  @JsonIgnore
  @Transient
  protected UUID uuid = UUID.randomUUID();

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    AbstractBaseEntity that = (AbstractBaseEntity) o;
    return uuid.equals(that.getUuid());
  }

  @Override
  public int hashCode() {
    return uuid.hashCode();
  }

  public AbstractBaseEntity(long version) {
    this.version = version;
  }

  public AbstractBaseEntity() {
  }
}

我使用以下方法创建了一个培训存储库JpaRepository

@Repository
interface TrainingRepository extends JpaRepository<Training, Long> {

  List<Training> findAllByTrainingParticipants_Trainer_IdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual(
      Long trainerId,
      LocalDateTime trainingStartDate,
      LocalDateTime trainingEndDate);

  default List<Training> findAllTrainerTrainingsBetweenStartAndEndDate(
      Long trainerId,
      LocalDateTime trainingStartDate,
      LocalDateTime trainingEndDate) {

    return findAllByTrainingParticipants_Trainer_IdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual(
        trainerId, trainingStartDate, trainingEndDate);
  }
}

使用 IntelliJ 提示,我创建了一个自定义查询,它将找出两个日期之间的所有培训师培训。问题是,通过上述方法,我收到了一个异常,如下所示:

Caused by: java.lang.IllegalArgumentException: Failed to create the query for method public abstract java.util.List com.application.training.TrainingRepository.findAllByTrainingParticipants_Trainer_IdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual(java.lang.Long,java.time.LocalDateTime,java.time.LocalDateTime)! Unable to locate Attribute  with the the given name [trainer] on this ManagedType [com.application.common.AbstractBaseEntity]

我有点困惑,因为过去当我与正常工作的 IDE 提示合作时。同时,我知道我可以使用经典的 SQL 方法,但在这种情况下 Spring Data 是可取的。我将不胜感激有关如何修复查询并达到目标的建议。

编辑:

对于没有_分隔符的变体,我有一个错误,例如:

Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.appplication.training.TrainingRepository.findAllByTrainingParticipantsTrainerIdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual(java.lang.Long,java.time.LocalDateTime,java.time.LocalDateTime)! Unable to locate Attribute  with the the given name [trainer] on this ManagedType [com.application.common.AbstractBaseEntity]

使用分隔符它看起来像:

Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.application.training.TrainingRepository.findAllByTrainingParticipants_Trainer_IdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual(java.lang.Long,java.time.LocalDateTime,java.time.LocalDateTime)! Unable to locate Attribute  with the the given name [trainer] on this ManagedType [com.application.common.AbstractBaseEntity]

编辑2:建议@Simon Martinelli 后出现如下错误:

Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.application.training.TrainingRepository.findAllByTrainingParticipants_Trainer_IdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual(java.lang.Long,java.time.LocalDateTime,java.time.LocalDateTime)!

标签: javahibernatespring-data-jpaspring-data

解决方案


您不能在像 trainingParticipants 这样的 ToMany 关系的查询中导航。

您必须加入这两个实体才能拥有 trainingParticipants 的别名。因此,您不能为此查询使用 Spring Data JPA 查询方法,而必须创建 JPQL 查询或规范。

@Query("select t from Training t join t.trainingParticipants p " +
       "where p.trainer id = :trainerId and t.trainingDate.startDate <= :trainingStartDate " +
       "and t.trainingDate.endDate <= :trainingEndDate")
List<Training> findTrainingOfTrainer(Long trainerId, LocalDateTime trainingStartDate, LocalDateTime trainingEndDate);

推荐阅读