解决多态子类属性jpa hibernate查询的标准

时间:2013-09-12 16:27:25

标签: java hibernate jpa criteria-api

将hibernate 3.6.10与hibernate jpa 2.0一起使用。

我的问题归结为需要在稍微复杂的加入查询期间在子对象的列上设置一些条件。

我有一组类似于:

的对象
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Ball 
{
     private String name;
     //...getter and setter crud...
}


@Entity
public class BeachBall extend ball
{
    private boolean atTheBeach;
     //...getter and setter crud...

}

@Entity
public class SoccerBall extend ball
{
    private int numberOfKicks;
     //...getter and setter crud...
}

@Entity
public class Trunk 
{

    private Set<Ball> balls;


     @OneToMany(mappedBy = "trunk", cascade = CascadeType.ALL, orphanRemoval = true)
     public Set<Ball> getBalls()
     {
          return balls;
     }

}
@Entity
public class Car
{
    private Trunk trunk;
    private String carModel;

    //...getter and setter crud...
}

现在我需要查询有多少足球在有特定型号的赛车中有20次踢球。

使用JPA我尝试做类似的事情:

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Car> criteriaQuery = criteriaBuilder.createQuery(Car.class);
    Root<Car> car= criteriaQuery.from(Car.class);
    Join<Car, Trunk> trunkJoin = car.join(Car_.trunk);
    Join<Trunk, Ball> ballJoin = trunkJoin.join(Trunk_.Balls);
    criteriaQuery.select(trunk);
    Predicate [] restrictions = new Predicate[]{  criteriaBuiler.equal(car.get(carModel), "Civic"), criteriaBuilder.equal(ballJoin.get("numberOfKicks"), 20)};
    criteriaQuery.where(restrictions);
    TypedQuery<Car> typedQuery = entityManager.createQuery(criteriaQuery);
    Car carWithSoccerBalls = typedQuery.getSingleResult();

在运行时,上面的代码会死掉,因为numberOfKicks只在soccerball上,并且由于它在Trunk中输入的方式,它只知道球。如果我手动创建一个从足球和设置标准加入它我可以查询numberOfKicks,但我觉得必须有一种方法来通知查询该集实际上是一个集。

请注意我无法发布任何实际代码,因此以上所有示例都只是示例。

如上所述使用JPA和hibernate是否有办法强制hibernate知道set&lt;球&gt;实际上是设置&lt; soccerball&gt;?

2 个答案:

答案 0 :(得分:3)

由于时间的限制,我采取了简单的方法:(。如果有人能够更好地回答那么我拥有的东西我很乐意选择他们的答案。

要使条件api认识到我正在寻找继承的表,我将查询代码更改为:

   CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Car> criteriaQuery = criteriaBuilder.createQuery(Car.class);
    Root<Car> car= criteriaQuery.from(Car.class);
    Root<Soccerball> soccerballs = criteriaQuery.from(SoccerBall.class);
    Join<Car, Trunk> trunkJoin = car.join(Car_.trunk);
    Join<Trunk, Ball> ballJoin = trunkJoin.join(Trunk_.Balls);
    criteriaQuery.select(trunk);
    Predicate [] restrictions = new Predicate[]{  criteriaBuiler.equal(car.get(carModel), "Civic"), criteriaBuilder.equal(soccerball.get("numberOfKicks"),20), criteriaBuilder.equal(soccerball.get(SoccerBall_.id),car.get(Car_.id))};
    criteriaQuery.where(restrictions);
    TypedQuery<Car> typedQuery = entityManager.createQuery(criteriaQuery);
    Car carWithSoccerBalls = typedQuery.getSingleResult();

答案 1 :(得分:1)

以下内容将检索具有嵌套列表属性的所有Car,这些属性满足集合中子类类型的相等性条件以及根元素上的相等性。 我已修改查询以与原始问题中的数据模型一起使用。

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Car> carQuery = criteriaBuilder.createQuery(Car.class);
Root<Car> carRoot = carQuery.from(Car.class);

Subquery<SoccerBall> ballQuery = carQuery.subquery(SoccerBall.class);
Root<SoccerBall> soccerBall = ballQuery.from(SoccerBall.class);

ballQuery.select(soccerBall);
ballQuery.where(criteriaBuilder.equal(soccerBall.get(SoccerBall_.numberOfKicks), 25));

Join<Car, Trunk> carTrunkJoin = carRoot.join(Car_.trunk);
SetJoin<Trunk, Ball> trunkBallJoin = carTrunkJoin.join(Trunk_.balls);

carQuery.select(carRoot);
carQuery.where(criteriaBuilder.and(
    trunkBallJoin.in(ballQuery),
    criteriaBuilder.equal(carRoot.get(Car_.carModel), "Civic")));


TypedQuery<?> typedQuery = entityManager.createQuery(carQuery);
List<?> result = typedQuery.getResultList();

等效的SQL是:

SELECT * FROM car JOIN trunk JOIN ball WHERE ball.id IN (SELECT soccerball.id FROM soccerball WHERE soccerball.numberOfKicks = 25)