Предикаты API JPA Criteria для объектов в отношениях OneToMany - PullRequest
1 голос
/ 14 февраля 2012

Учитывая следующий код

@Entity
public class Invoice {

  @GeneratedValue(strategy = GenerationType.AUTO)
  @Id
  public Long id;

  @Embedded
  private InvoiceData data = new InvoiceData();
} 


@Embeddable
public class InvoiceData {
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  public Collection<InvoiceLineItem> lineItems;
}

@Entity
public abstract class InvoiceLineItem {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @Column
  private String description;
}

@Entity
public class GoodsLineItem extends InvoiceLineItem {

}

@Entity
public class CostLineItem extends InvoiceLineItem {

}

Как бы я написал API-запрос критерия, который возвращает все счета-фактуры с CostLinesItem, описание которого равно "TAX"?

Я использую API метаданных,Я пробовал различные подходы, большинство из которых являются вариациями 2, перечисленных ниже.Будем весьма благодарны за любые указатели / помощь или прочитайте это.

Попытка 1 (из многих):

@Test
public void criteria_api_and_collections() throws Exception {

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Invoice> query = builder.createQuery(Invoice.class);
    Root<Invoice> root = query.from(Invoice.class);

    Join<InvoiceData, InvoiceLineItem> lineItems = root.join(Invoice_.data).join(InvoiceData_.lineItems);

    query.where(builder.equal(lineItems.get(InvoiceLineItem_.description), ""));
    List<Invoice> resultList = em.createQuery(query).getResultList();

    System.out.println(resultList);
}

Попытка 2 (из многих):

@Test
public void criteria_api_and_collections() throws Exception {

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Invoice> query = builder.createQuery(Invoice.class);
    Root<Invoice> root = query.from(Invoice.class);

    Join<InvoiceData, InvoiceLineItem> lineItems = root.join(Invoice_.data).join(InvoiceData_.lineItems, JoinType.LEFT);

    Subquery<CostLineItem> subquery = query.subquery(CostLineItem.class);
    Root<CostLineItem> fromLineItem = subquery.from(CostLineItem.class);
    subquery.select(fromLineItem);
    subquery.where(builder.equal(lineItems.get(InvoiceLineItem_.description), "TAX"));

    query.where(builder.in(lineItems).value(subquery));

    List<Invoice> resultList = em.createQuery(query).getResultList();
}

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

Ответы [ 2 ]

0 голосов
/ 21 февраля 2012

Я поменял Hibernate 4.1.0.Final на EclipseLink 2.0.0, и он заработал.

0 голосов
/ 15 февраля 2012

Я не могу сейчас выполнить тест, но, следуя Java EE 6 Tutorial , мы видим, что

Встраиваемые классы могут также содержать отношения к другим объектамили коллекции лиц.Если у встраиваемого класса есть такая связь, это связь между целевым объектом или набором сущностей и сущностью, которой принадлежит встраиваемый класс.

Это заставляет меня думать, что предикат Join должен бытьопределяется с помощью начальной сущности Invoice вместо InvoiceData.И это также подтверждается тем фактом, что обычно исходной сущностью должен быть сам корень запроса.Я бы попробовал что-то вроде этого:

Join<Invoice, InvoiceLineItem> lineItems = root.join(Invoice_.data).join(InvoiceData_.lineItems);
...