JPA Criteria API объединяет 3 таблицы и некоторые нулевые элементы

У меня есть один родительский объект, который имеет два дочерних объекта в качестве атрибутов. Я хочу выбрать все элементы из родительского объекта, у которых есть ЛИБО childOne с заданным параметром в качестве личного атрибута ИЛИ childTwo с тем же заданным параметром в качестве личного атрибута.

Вот мои три упрощенных класса:

Родительский объект:

@Entity
public class ParentObject {

    @Id
    private int id;

    private int fkChildOne;

    private int fkChildTwo;

    @ManyToOne
    @JoinColumn(name = "fk_child_one_id", referencedColumnName = 
    "child_one_id")
    private ChildOne childOne;

    @ManyToOne
    @JoinColumn(name = "fk_child_one_id", referencedColumnName = 
    "child_one_id")
    private ChildTwo childTwo;

// getters and setters

}

Дочерний объект:

@Entity 
public class ChildOne {

    @Id
    private int childOneId;

    private String nameChildOne;

    @OneToMany
    @JoinColumn(name = "fk_child_one_id")
    private List<ParentObject> parents;


// getters and setters

}

Дочерний объект Two:

@Entity
public class ChildTwo {

    @Id
    private int childOneId;

    private String nameChildTwo;

    @OneToMany
    @JoinColumn(name = "fk_child_two_id")
    private List<ParentObject> parents;


// getters and setters

}

Класс спецификаций:

   public static Specification<ParentObject> checkName(String name) {

     return Specifications.where(
             (root, query, builder) -> {

                 final Join<ParentObject, ChildOne> joinchildOne = 
                 root.join("childOne");

                 final Join<ParentObject, ChildTwo > joinchildTwo = 
                 root.join("childTwo");

                 return builder.or(
                         builder.equal(joinchildOne .get("nameChildOne"), name),
                         builder.equal(joinchildTwo .get("nameChildTwo"), name)
                         );
             }
     );
    }

Когда эта спецификация вызывается в моей службе, я не получаю никаких результатов. Однако, если я закомментирую одно из двух соединений и соответствующий предикат в моем методе builder.or, то я получу некоторые результаты, но они, очевидно, не соответствуют тому, что я ищу, то есть выбрать каждый ParentObject, у которого есть либо ChildOne с этим параметром или ChildTwo с этим параметром.

Любая подсказка, что не так с кодом?


person Alexandra Courtiol    schedule 16.06.2020    source источник
comment
Не могли бы вы указать корневую сущность, сущность автомобиля и метод, с помощью которого вы выполняете выборку?   -  person JLazar0    schedule 16.06.2020
comment
@ JLazar0 Я обновил свой пост, чтобы он был понятнее. Вы заметили проблему?   -  person Alexandra Courtiol    schedule 16.06.2020
comment
Первое, что я вижу, это отсутствие аннотации @JoinColumn (name = COLUMN) для дочерних элементов. Я также не вижу аннотацию @Id. Моделирование объектов важно, вы делаете это вручную, используете ли вы eclipse? Вы работаете над моделью данных?   -  person JLazar0    schedule 16.06.2020
comment
@ JLazar0 Спасибо за ответ. Я обновил сообщение с лучшим кодом, так как он действительно был неполным. Я все еще не получаю ожидаемых результатов с помощью моего метода builder.or. Есть еще совет?   -  person Alexandra Courtiol    schedule 16.06.2020


Ответы (2)


Наконец, пришло решение: чтобы получить все соответствующие результаты, мне пришлось добавить тип соединения, который будет левым соединением, поскольку я хотел получить все ParentObjects независимо от того, владею ли объектами childOne или ChildTwo.

final Join<ParentObject, ChildOne> joinchildOne = 
                 root.join("childOne", JoinType.LEFT);

                 final Join<ParentObject, ChildTwo > joinchildTwo = 
                 root.join("childTwo", JoinType.LEFT);
person Alexandra Courtiol    schedule 17.06.2020

Отлично, теперь вам нужно выбрать, нужно ли вам присоединиться или получить. Чтобы оптимизировать запрос и память, вы должны установить отношения как Lazy (@ManyToMany (fetch = FetchType.LAZY)), поэтому вы будете приносить только те объекты, которые вы требуете.

Основное отличие состоит в том, что Join определяет пересечение таблиц в переменной и позволяет вам использовать ее для извлечения определенных полей в предложении select, например, с другой стороны, fetch заставляет передавать все объекты этого свойства. В вашем примере выбор из родителя с объединением дочерних элементов (после того, как отношение установлено на ленивый) приведет только к инициализированным объектам родительского типа, однако, если вы выполните выборку, он приведет к инициализации родительских и дочерних объектов.

Еще одно изменение, которое я бы сделал, это изменить тип идентификатора на непримитивный, чтобы он принимал нулевые значения, необходимые для вставки с использованием последовательностей.

person JLazar0    schedule 17.06.2020