JPA LOJ (левое внешнее соединение): невозможно присоединить к атрибуту базового типа - PullRequest
0 голосов
/ 01 мая 2019

У меня есть две сущности, которые я хочу сделать LOJ на использование JPA и запрос критерия. Звучит достаточно просто, но я столкнулся с проблемой. Мои сущности:

@Data
@ToString
@Entity
@Table(name = "TABLE1")
public class Table1 {
       @Id
       @SuppressWarnings("all")
       @Column(name = "ROWID")
        private String rowId;

       @Column(name = "SOME_ID")
       private String someId;
       ....
       @ManyToMany
       @JoinColumn(name = "SOME_ID", referencedColumnName = "SOME_ID")
       private List<Table2> table2s;
}

и

@Data
@ToString
@Entity
@Table(name = "TABLE2")
public class Table2 implements Serializable {

    @Id
    @SuppressWarnings("all")
    @Column(name = "ROWID")
    private String rowId;

   @Column(name = "SOME_ID")
    private String someIdAsId;
   ....

   @ManyToMany(fetch = FetchType.LAZY, mappedBy = "table2s")
   private List<Table1> table1s;
}

Мои критерии запроса / присоединения:

        EntityManager em = getEntityManager();
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Object> criteriaQuery = cb.createQuery();
        criteriaQuery.distinct(true);
        Root<Table1> previewSearch = criteriaQuery.from(Table1.class);

        if(searchFields.contains(A_FILE)) {
            Join<Table1, Table2> join = previewSearch.join("someId", JoinType.LEFT);
        }

Позже я добавлю критерии фильтра для файла reg, например:

predicates.add(cb.like(cb.trim(cb.lower((previewSearch.get("aFileNo")))), "%" + legacySearchCriteria.getAFileNo() + "%"));

затем добавьте преды к запросу:

criteriaQuery.select(previewSearch).where(predicates.toArray(new Predicate[]{}));

, то:

Query query = em.createQuery(criteriaQuery);
List<Table1> results = getResults(query);

Код получения результатов и все доказано. Это не проблема. Это как-то связано с тем, как мои сущности аннотированы или похожи. Когда я запускаю запрос, когда у меня есть «AFile» в запросе (запускающий создание объекта Join в моем коде), я получаю трассировку стека, базовая ошибка которой:

Caused by: org.hibernate.jpa.criteria.BasicPathUsageException: Cannot join to attribute of basic type
at org.hibernate.jpa.criteria.path.AbstractFromImpl.constructJoin(AbstractFromImpl.java:254)
at org.hibernate.jpa.criteria.path.AbstractFromImpl.join(AbstractFromImpl.java:247)
at org.hibernate.jpa.criteria.path.AbstractFromImpl.join(AbstractFromImpl.java:422)
at com.xxx.ent.dataobjects.common.dao.SearchDao.executeQuery(PreviewConditionalSearchDao.java:77)
at com.xxx.ent.dataobjects.common.dao.SearchDao.getPreview(PreviewConditionalSearchDao.java:46)
at sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

Я попал на этот сайт и др. и ничто там не выглядит, как будто это исправляет меня, хотя я попробовал несколько вещей. У кого-нибудь есть идеи?

---- ОБНОВЛЕНИЕ ----

По сути, я хотел сделать:

select fields from Table1 t1 left join Table2 t2 on t1.f1=t2.f1 where t2.f2 = 'somevalue'

Извлеченные уроки: f1 должен быть столбцом Id объединяемых сущностей JPA, иначе вы его не получите. Окончательный ответ выглядит так:

Объекты:

 @Data
 @ToString
 @Entity
 @Table(name = "TABLE_1")
 public class Table1 {
   @Id
   @Column(name = "ID")
   private String id;
 ....
   @ManyToOne(fetch=FetchType.LAZY)
   @JoinColumn(name = "ID", referencedColumnName = "ID", insertable=false, updatable=false)
   private Table2 table2;
 }

и

@Data
@ToString
@Entity
@Table(name = "TABLE_2")
public class Table2 {

 @Id
 @Column(name = "ID")
 private String id;

 @Column(name = "FIELD_2")
 private String f2;

 @OneToMany(fetch = FetchType.LAZY, mappedBy = "table2")
 private List<Table1> table1s;
}

Код:

EntityManager entityManager = getEntityManager();
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = cb.createQuery();
criteriaQuery.distinct(true);
Root<Table1> table1Root = criteriaQuery.from(Table1.class);
Path field2Path = null;

if(searchFields.contains(FIELD2)) {
   Join<Table1, Table2> field2Join = table1Root.join("table2", JoinType.LEFT);
    field2Path = field2Join.get("f2");
}

List<Predicate> predicates = new ArrayList<>();

// add preds ...
case SOME_PRED:              
  predicates.add(cb.like(cb.trim(cb.lower((table1Root.get("somePred")))), "%" + criteria.getSomePred() + "%"));
  break;
case FIELD2:
  predicates.add(cb.like(cb.trim(cb.lower((field2Path))), "%" + criteria.getField2() + "%"));
  break;

....
criteriaQuery.select(table1Root).where(predicates.toArray(new Predicate[]{}));
Query query = entityManager.createQuery(criteriaQuery);

Затем запустите запрос. Это действительно работает. Наконец-то.

1 Ответ

1 голос
/ 01 мая 2019

Объединение образует совокупность двух типов сущностей, давая кортежи сущностей. Ожидается, что вы назначите атрибут, определяющий отношение, характеризующее объединение, а не столбец объединения. Примерно так:

        Join<Table1, Table2> join = previewSearch.join("table2s", JoinType.LEFT);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...