получить только одного ребенка в JPA CriteriaBuilder Join Query - PullRequest
0 голосов
/ 10 марта 2020

У меня есть 2 объекта:

public class Tyre {

 @Id
 @Column(name = "tyreid")
 @GeneratedValue
 private int tyreid;
 @Column(name = "brand")
 private String brand;
 @Column(name = "tyretype")
 private String tyretype;
 @OneToMany(targetEntity = TyreAuto.class, cascade = CascadeType.ALL)
 @JoinColumn(name = "tyreid",referencedColumnName = "tyreid")
 private List<TyreAuto> tyreAutos;
}

и:

public class TyreAuto {
 @Id
 @Column(name = "tyreautoid")
 @GeneratedValue
 private int tyreautoid;
 @Column(name = "serie")
 private String serie;
 @Column(name = "tyreid")
 private int tyreid;
}

И у меня есть следующий код, который возвращает json ответ:

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Tyre> criteriaQuery = criteriaBuilder.createQuery(Tyre.class);
    Metamodel m = entityManager.getMetamodel();
    EntityType<Tyre> Tyre_ = m.entity(Tyre.class);
    Root<Tyre> tyreRoot = criteriaQuery.from(Tyre_);
    Join<Tyre,TyreAuto> tyreAutos = tyreRoot.join("tyreAutos",JoinType.INNER);

    Predicate predicateForBrand
            = criteriaBuilder.equal(tyreRoot.get("brand"), "Firestone");
    Predicate predicateForSerie
            = criteriaBuilder.equal(tyreAutos.get("serie"),"XYZ");
    Predicate predicateForBrandAndSerie
            = criteriaBuilder.and(predicateForSerie,predicateForBrand);
    criteriaQuery.where(predicateForBrandAndSerie);
    List<Tyre> items = entityManager.createQuery(criteriaQuery).getResultList();

    if (!items.equals(null)) {
        return new ResponseEntity<>(items, HttpStatus.OK);
    } else {
        return new ResponseEntity(ResponseEntity.notFound().build(),HttpStatus.NOT_FOUND);
    }

это возвращает следующее Json:

[
   {
    "tyreid": 1,
    "brand": "Firestone",
    "tyretype": "Big",
    "tyreAutos": [
        {
            "tyreautoid": 38,
            "serie": "XYZ",
            "tyreid": 13
        },
        {
            "tyreautoid": 39,
            "serie": "ABC",
            "tyreid": 13
        },
        {
            "tyreautoid": 40,
            "serie": "JKL",
            "tyreid": 13
        }
      ]
    }
 ]

Мой вопрос:

  • Почему я получаю несколько дочерних регистров, если я фильтрую для Ser ie: "XYZ"?
  • Как я могу получить только один дочерний элемент вместо всех 3?

Как я могу отфильтровать таким образом, чтобы ответ был примерно таким:

[
   {
    "tyreid": 1,
    "brand": "Firestone",
    "tyretype": "Big",
    "tyreAutos": [
        {
            "tyreautoid": 38,
            "serie": "XYZ",
            "tyreid": 13
        }
      ]
    }
 ]

1 Ответ

1 голос
/ 11 марта 2020

Почему я получаю несколько дочерних регистров, если я фильтрую для Ser ie: "XYZ"?

Вы получаете целый Tyre объект как объявлено criteriaBuilder.createQuery(Tyre.class) где brand = "Firestone" и tyreAutos содержит tyreAuto с serie = "XYZ".

Как получить только один дочерний элемент вместо всех 3?

Чтобы получить только один TyreAuto вы можете использовать обратный запрос, подобный этому criteriaBuilder.createQuery(TyreAuto.class), изменяя вашу сущность таким образом

public class TyreAuto {
    @Id
    @Column(name = "tyreautoid")
    @GeneratedValue
    private int tyreautoid;

    @Column(name = "serie")
    private String serie;

    @ManyToOne
    @JoinColumn(name = "tyreid")
    private Tyre tyre;
}

Теперь у вас есть доступ к tyre с TyreAuto

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<TyreAuto> criteriaQuery = criteriaBuilder.createQuery(TyreAuto.class);
Metamodel m = entityManager.getMetamodel();
EntityType<TyreAuto> TyreAuto_ = m.entity(TyreAuto.class);
Root<TyreAuto> tyreAutoRoot = criteriaQuery.from(TyreAuto_);
Join<TyreAuto, Tyre> tyre = tyreAutoRoot.join("tyre",JoinType.INNER);

Predicate predicateForBrand
        = criteriaBuilder.equal(tyre.get("brand"), "Firestone");
Predicate predicateForSerie
        = criteriaBuilder.equal(tyreAutoRoot.get("serie"),"XYZ");

criteriaQuery.select(tyreAutoRoot).where(predicateForSerie, predicateForBrand);
List<TyreAuto> items = entityManager.createQuery(criteriaQuery).getResultList();

Другой вариант - использовать класс dto в качестве результата запроса. Вы можете настроить это вам нужно. Здесь вы можете получить больше информации. Прочитайте главу Прогнозы DTO в запросах критериев

...