Запросы JPA в отношениях OneToMany работают не так, как ожидалось - PullRequest
0 голосов
/ 25 мая 2020

Учитывая следующий Questionnaire объект ...

@Entity
@Table(name = "questionnaire")
@EntityListeners(AuditingEntityListener.class)
@Getter
@Builder
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class Questionnaire {

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

  ...

  @Builder.Default
  @OneToMany(
      mappedBy = "questionnaire",
      fetch = FetchType.LAZY,
      cascade = {CascadeType.ALL})
  private List<Definition> definitionVersions = new ArrayList<>();
}

... и следующий Definition объект:

@Entity
@Table(name = "definition")
@IdClass(VersionPk.class)
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
@Builder
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class Definition implements Comparable<Definition>, Persistable<Long> {

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

  @Id
  @Column(name = "version", nullable = false)
  private Integer version;

  ...

  @ManyToOne
  @JoinColumn(name = "definition_id", nullable = false, referencedColumnName = "id")
  private Questionnaire questionnaire;

  @Builder.Default
  @OneToMany(
      mappedBy = "definition",
      fetch = FetchType.LAZY,
      cascade = {CascadeType.ALL})
  private List<Questionnaire> questionnaires = new ArrayList<>();
}

... и для полноты:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
@EqualsAndHashCode
public class VersionPk implements Serializable {

  private Long id;
  private Integer version;
}

Например, описанный выше механизм предназначен только для управления множеством версий одного и того же вопросника. Теперь предположим, что я хочу получить версию 2 анкеты ... вот мой собственный запрос:

@Repository
public interface QuestionnaireRepository extends JpaRepository<Questionnaire, Long> {

  String QUERY_FIND_BY_ID_AND_VERSION =
    "select q from Questionnaire q"
      + " join q.definitionVersions v"
      + " where q.id = ?1 and v.version = ?2";

  @Query(value = QUERY_FIND_BY_ID_AND_VERSION)
  Optional<Questionnaire> findByIdAndVersion(Long id, Integer version);

  ...
}

Я ожидал, что definitionVersions в Questionnaire содержит только указанные Definition версия; вместо этого я всегда получаю все definitions, связанные с данным Questionnaire. Я что-то упустил?

1 Ответ

1 голос
/ 26 мая 2020

Вы фильтруете анкету с версией = 2, но запрашиваемая анкета не является полной, если она не содержит всех деталей (и определений), которые вы ей сопоставили. JPA не применяет фильтры к самим результатам запроса - некоторые провайдеры JPA позволяют использовать перехватчики, но это обычно вызывает проблемы, когда управляемый объект «сохраняется» обратно, поскольку данные в нем являются неполными.

Если вам нужна только пара определение / вопросник, поместите их в свой запрос для выбора:

String QUERY_FIND_BY_ID_AND_VERSION =
    "select v, q from Questionnaire q"
      + " join q.definitionVersions v"
      + " where q.id = ?1 and v.version = ?2";

Затем будет возвращен список, содержащий объект [2], содержащий определение и анкету для каждого результата, который соответствует . Используйте это Определение вместо доступа к списку версий определений Анкеты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...