【问题标题】:Is it possible to implement an exists query based on @ElementCollection using Jpa criteria query?是否可以使用 Jpa 条件查询实现基于 @ElementCollection 的存在查询?
【发布时间】:2013-08-16 10:00:44
【问题描述】:

我正在学习 Jpa 条件查询,但不知道如何实现:

我有一个名为 Restaurant 的实体:

@Entity
@Table(name = "t_f2g_restaurant", 
    uniqueConstraints = @UniqueConstraint(columnNames = { "NAME" }))
public class Restaurant {
    @EmbeddedId
    @AttributeOverrides(
        { @AttributeOverride(name = "value", column = @Column(name = "ID")) })
    private RestaurantIdentity id;

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

    @ElementCollection
    @CollectionTable(name = "t_f2g_restaurant_srv_area", 
        joinColumns = @JoinColumn(name = "RESTAURANT_ID"))
    @Column(name = "zip_code")
    private List<String> serviceAreas = new ArrayList<String>();
}

现在我想统计按 serviceAreas 过滤的餐馆,下面是我的原生 sql 实现:

private boolean delegateToNativeQuery(Address deliveryAddress {
    String sqlString = "select count(*) from t_f2g_restaurant r "
        + "where exists (select * from t_f2g_restaurant_srv_area sa "
        + "where sa.zip_code = ? and r.id = sa.restaurant_id) ";

    Query query = entityManager.createNativeQuery(sqlString);
    query.setParameter(1, deliveryAddress.getZipCode());
    return ((Number) query.getSingleResult()).longValue() > 0;
}

但是如何通过条件查询来实现呢?

以下是我的尝试:

private boolean delegateToCriteriaQuery(Address deliveryAddress) {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
    Root<Restaurant> restaurant = query.from(Restaurant.class);

    Subquery<Long> serviceAreaSubquery = query.subquery(Long.class);

    /* This causes an extra t_f2g_restaurant, t_f2g_restaurant_srv_area join 
    Root<Restaurant> serviceAreaRoot = serviceAreaSubquery
        .from(Restaurant.class);

    ListJoin<Restaurant, String> serviceAreas = serviceAreaRoot
        .joinList("serviceAreas");
    serviceAreaSubquery.select(criteriaBuilder.count(serviceAreaRoot))
        .where(criteriaBuilder.
            //serviceArea is represented by String, so what's the attribute name?
            equal(serviceAreas.get("serviceArea"), deliveryAddress.getZipcode()));

    query.select(criteriaBuilder.count(restaurant)).
        where(criteriaBuilder.exists(serviceAreaSubquery));

    return entityManager.createQuery(query).getSingleResult() > 0;
}

【问题讨论】:

    标签: jpa jpa-2.0 criteria-api


    【解决方案1】:

    我刚刚做到了。希望答案对某人有所帮助。

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Restaurant> query = criteriaBuilder
        .createQuery(Restaurant.class);
    
    Root<Restaurant> restaurants = query.from(Restaurant.class);
    
    Subquery<Restaurant> serviceAreasFiltering = query
        .subquery(Restaurant.class);
    
    ListJoin<Object, Object> serviceAreas = serviceAreasFiltering
        .correlate(restaurants).joinList("serviceAreas");
    //correlate joins t_f2g_restaurant and t_f2g_restaurant_srv_area
    
    serviceAreasFiltering.where(criteriaBuilder.or(
        criteriaBuilder.equal(serviceAreas, deliveryAddress.getStreet1()),
        //equal against serviceAreas for I use List<String> for serviceAreas
        criteriaBuilder.equal(serviceAreas, deliveryAddress.getStreet2())));
    
    query.where(criteriaBuilder.exists(serviceAreasFiltering));
    
    return entityManager.createQuery(query).getResultList();
    

    坦率地说,在这种情况下,我认为标准 api 并不容易阅读。除非我需要返回餐馆列表,否则我可能不会切换到条件 api(如果使用本机 sql 查询,我需要编写结果映射器)。

    【讨论】:

      猜你喜欢
      • 2013-01-21
      • 2018-01-13
      • 1970-01-01
      • 2012-08-19
      • 2021-02-17
      • 1970-01-01
      • 2017-05-22
      • 1970-01-01
      • 2014-01-07
      相关资源
      最近更新 更多