Crinteria присоединяется к make И вставке OR

#java #criteria #hibernate-criteria #criteria-api

#java #критерии #переход в спящий режим-критерии #критерии-api

Вопрос:

Моя проблема в том, что когда я устанавливаю cb.или он делает cb и .. cb является CriteriaBuilder, мой класс :

 public class User extends BaseEntity<User> {
public static final String CHILDREN_FIELD = "children";
public static final String PARENT_FIELD = "parent";

//Id column based in BaseEntity

OneToOne(fetch = LAZY)
JoinColumn(name = "parent_partner_id")
User parent;

OneToMany(mappedBy = "parent", fetch = LAZY,cascade = {})
private List<User> children;
  

Мой критерий кода :

 Root<User> root = query.from(User.class);
Join<User, User> userJoin = root.join(CHILDREN_FIELD, JoinType.LEFT);
userJoin.on(
cb.or(
cb.equal(userJoin.get(ID_FIELD), root.get("id")))
);
  

Код генерирует :

 select
user0_.id as col_0_0_
from
user user0_
left outer join
user children2_
on user0_.id=children2_.parent_id
and (  <- i write OR in cb!! why it generates AND ?  
children2_.id=user0_.id
)
  

Как я могу это решить? Почему мой код генерирует оператор AND?

Комментарии:

1. Привет, имеет ли смысл этот запрос с точки зрения SQL? Я этого не понимаю.

2. Я использую postgesql

Ответ №1:

Вероятно, это потому, что у вас есть один аргумент в вашем вызове метода or

 cb.or(cb.equal(userJoin.get(ID_FIELD), root.get("id"))));
  

должно быть

 cb.or(arg1, arg2); // arg1 OR arg2
  

Ответ №2:

Мне жаль говорить вам, что с критериями API сегодня это невозможно, я расскажу вам о разных вариантах:

1.- Использовать собственный запрос

Использование собственного запроса не является проблемой, поскольку вы используете предложения, поддерживаемые всеми менеджерами БД

 List<User> result =  em.createNativeQuery("select * from user p " 
                        "left outer join user p1 on p.id = p1.parent_id or p.id = p1.id", 
                        "User.nativeConstructorMapping").getResultList();
  

В вашей сущности

 @SqlResultSetMappings({
    @SqlResultSetMapping(name="User.nativeConstructorMapping",
    classes = {
    @ConstructorResult(
        targetClass = Users.class,
        columns = {
            @ColumnResult(name = "id", type = Long.class),
            @ColumnResult(name = "name", type = String.class)
            [...]
        })
    })
})

....

public User(Long id, String name, [...]) {
    super();
    this.id= id;
    this.name = name
    [...]
}
  

2.- Используйте два корня, на случай, если вместо left join вам подойдет inner join, добавив условия предложения on в where

 CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root1 = query.from(User.class);
Root<User> root2 = query.from(User.class);

query.where(cb.or(
    cb.equal(root1.get(User_.id),root2.get(User_.parent).get(User_.id)),
    cb.equal(root1.get(User_.id),root2.get(User_.id)))
);
  

Как я вам говорил, хотя не рекомендуется использовать собственные запросы, потому что это противоречит философии JPA, в этом случае, поскольку вы не используете предложения какой-либо базы данных, это не должно быть проблемой, я бы выбрал тот вариант, который я бы выбрал.