2012-02-17 80 views
4

从连接表中选择对象我正在为下面的问题争取两天时间,并希望您能够推动我朝着正确的方向前进。我在研究中发现的教程和示例总是只显示了如何轻松加入标准api。首先我有两个类:使用JPA Criteria-API

@Entity 
public class Offer { 

    private String name; 
    @ManyToOne private Location location; 
    private String tags; 
} 

@Entity 
public class Location { 
    private String name; 
    private string tags; 
} 

因为我需要避免循环引用beween这些类的连接仅仅是单向的。在这个类中有很多附加属性,我想根据我的搜索过滤器来构建动态查询。下面的SQL语句将解释什么,我喜欢做的事:

SELECT l 
FROM Offer o 
JOIN o.location l 
WHERE o.tags LIKE :sometag AND l.tags LIKE :someothertag 

与标准的API,我得到这个代码实现之后:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 
CriteriaQuery<Location> criteriaQuery = criteriaBuilder.createQuery(Location.class); 
criteriaQuery = criteriaQuery.distinct(true); 
Join location; 
ArrayList<Predicate> whereList = new ArrayList<Predicate>(); 

// if filter by offer, use offer as main table and join location table 
if (filter.getOfferTags() != null) { 
    Root<Offer> offer = criteriaQuery.from(Offer.class); 

    location = offer.join("location"); 


    // limit to offering tags 
    Path<String> tagPath = offer.get("tags"); 

    for (String tag : filter.getOfferTags()) { 
    Predicate whereTag = criteriaBuilder.like(tagPath, "%" + tag + "%"); 
    whereList.add(whereTag); 
    } 

} else { 
    // else use location table as base 
    location = (Join<Location, Location>) criteriaQuery.from(Location.class); 
} 

但如果我执行此我收到以下错误信息从我的H2数据库:

Column "LOCATION.ID" not found; SQL statement: 
SELECT DISTINCT LOCATION.ID, LOCATION.NAME 
FROM OFFER t0, LOCATION t1 
WHERE t0.TAGS LIKE ? AND t1.TAGS LIKE ? 

数据库预计t1.ID和SELECT子句中t1.NAME而不是LOCATION.IDLOCATION.NAME。我如何告诉JPA创建“正确”请求?我在代码中丢失了什么吗?

我使用Glassfish 3.1.1与Eclipse Link和H2数据库。

回答

6

我认为你只是错过在查询一个选择:

criteriaQuery.select(location); 
+0

非常感谢。现在它可以工作。 – Ralph 2012-02-17 15:30:16

4

我不认为你需要显式指定在查询中加入 - 毕竟报价已经有一个映射位置。

像这样的东西就足够了:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Location> cq = criteriaBuilder.createQuery(Location.class); 
Root<Offer> offer = criteriaQuery.from(Offer.class); 
cq.select(offer.get("location")); 
cq.where(...)