0

I want to create a custom Spring Data query which will find all training for a trainer between two dates.

Training class looks like:

@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;
}

with nested classes like:

@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;
}

and

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

  @Id
  @GeneratedValue
  private Long id;

  private LocalDateTime startDate;

  private LocalDateTime endDate;
}

AbstractBaseEntity for HashCodeEquals contract and @Version usage looks like:

@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() {
  }
}

I created a Training repository with JpaRepository usage with method like:

@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);
  }
}

With IntelliJ hints, I created a custom query which will find out all training of trainer between two dates. Problem is that with the above approach I am receiving and an exception which looks like below:

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]

I am a little bit confused because in the past when I was cooperating with IDE hints that were working properly. At the same time, I understand that I can use the classic SQL approach but in this scenario Spring Data is desirable. I will be grateful for a suggestions on how to fix a query and reach a goal.

EDIT:

for variant without _ separator I have an error like:

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]

with separators it's looks like:

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]

EDIT 2: After suggestion @Simon Martinelli there is an error like:

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)!
6
  • Why do you have _ in the method signature? Use Camel Case Commented Nov 15, 2019 at 11:50
  • @SimonMartinelli Thanks for your answer, it's used for a nested object in a class training. After removing it this is still not working. Commented Nov 15, 2019 at 11:54
  • Can you please update the Exception Message Commented Nov 15, 2019 at 12:14
  • @SimonMartinelli unfortunately, the error is the same while startup application. Commented Nov 15, 2019 at 12:48
  • Btu you get findAllByTrainingParticipants_Trainer_IdAndTrainingStartDateLessThanEqualAndTrainingEndDateGreaterThanEqual and I said remove the _ then it should be another message Commented Nov 15, 2019 at 13:05

1 Answer 1

1

You cannot navigate in a query over a ToMany relationship like trainingParticipants.

You have to join the two entities to have a alias for trainingParticipants. So you cannot use Spring Data JPA query methods for this query but have to create a JPQL query or a Specification.

@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);
Sign up to request clarification or add additional context in comments.

4 Comments

@Thank you so much for the answer. After ridding of a small typo p.trainerId and setting nativeQuery flag to true application starts without an error. I will check if the result of the query is proper as soon as possible. So far big + for you for a fast response.
No you don't have to set nativeQuery to ture. It's not a native Query!
thanks for the patience. Problem is that without this flag application is not starting. I posted an error as an edit part. I understand that is not a native query, I checked this flag only for a test purpose because today I have a pretty weird problem with syntax and hints in IntelliJ which is completely not understandable for me.
Try to use another name for the method like findTrainingFromTrainer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.