title: JPA LOJ (left outer join) : Cannot join to attribute of basic type
body: <p>I have two entities I want to do an LOJ on using JPA and a criteria query.  Sounds easy enough but I am running into a problem.  My entities:</p>
  
  <pre><code>@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&lt;Table2&gt; table2s;
  }
  </code></pre>
  
  <p>and</p>
  
  <pre><code>@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&lt;Table1&gt; table1s;
  }
  </code></pre>
  
  <p>My criteria query/join:</p>
  
  <pre><code>        EntityManager em = getEntityManager();
          CriteriaBuilder cb = em.getCriteriaBuilder();
          CriteriaQuery&lt;Object&gt; criteriaQuery = cb.createQuery();
          criteriaQuery.distinct(true);
          Root&lt;Table1&gt; previewSearch = criteriaQuery.from(Table1.class);
  
          if(searchFields.contains(A_FILE)) {
              Join&lt;Table1, Table2&gt; join = previewSearch.join("someId", JoinType.LEFT);
          }
  </code></pre>
  
  <p>Later I add a filter criteria for reg file, as in:</p>
  
  <pre><code>predicates.add(cb.like(cb.trim(cb.lower((previewSearch.get("aFileNo")))), "%" + legacySearchCriteria.getAFileNo() + "%"));
  </code></pre>
  
  <p>then add the preds to the query:</p>
  
  <pre><code>criteriaQuery.select(previewSearch).where(predicates.toArray(new Predicate[]{}));
  </code></pre>
  
  <p>then:</p>
  
  <pre><code>Query query = em.createQuery(criteriaQuery);
  List&lt;Table1&gt; results = getResults(query);
  </code></pre>
  
  <p>The code around the getting of results and all is proven.  That isn't the issue.  It has something to do with the way I have my entities annotated or similar.  When I run the query when I have the "AFile" in the query (triggering the creation of a Join object in my code), I get a stacktrace whose base error is:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>I have hit this site et al. and nothing there looks like it has a fix for me, though I tried several things.  Anyone have ideas?</p>
  
  <p>---- UPDATE ----</p>
  
  <p>In essence I was looking to do a:</p>
  
  <pre><code>select fields from Table1 t1 left join Table2 t2 on t1.f1=t2.f1 where t2.f2 = 'somevalue'
  </code></pre>
  
  <p>Lessons learned: f1 must be the Id column of the JPA entities being joined or else you don't get it.  The final answer looks like this:</p>
  
  <p>Entities:</p>
  
  <pre><code> @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;
   }
  </code></pre>
  
  <p>and</p>
  
  <pre><code>@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&lt;Table1&gt; table1s;
  }
  </code></pre>
  
  <p>Code:</p>
  
  <pre><code>EntityManager entityManager = getEntityManager();
  CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  CriteriaQuery&lt;Object&gt; criteriaQuery = cb.createQuery();
  criteriaQuery.distinct(true);
  Root&lt;Table1&gt; table1Root = criteriaQuery.from(Table1.class);
  Path field2Path = null;
  
  if(searchFields.contains(FIELD2)) {
     Join&lt;Table1, Table2&gt; field2Join = table1Root.join("table2", JoinType.LEFT);
      field2Path = field2Join.get("f2");
  }
  
  List&lt;Predicate&gt; predicates = new ArrayList&lt;&gt;();
  
  // 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);
  </code></pre>
  
  <p>Then run the query.  That actuallly works.  Finally.</p>