HQL或SQL查询以从许多相关实体获取数据

时间:2019-08-14 00:47:50

标签: java mysql spring hibernate

我正在使用spring和hibernate将数据存储在MySql数据库中。我正在尝试根据用户请求的过滤器检索行。 我有以下表格/实体:产品和宝石

关系
  • 生产多很多宝石

我正在尝试编写查询,以获取具有宝石A和宝石B以及宝石C ..等的产品。

用例:

如果用户要求使用宝石51和46的产品。查询应仅返回产品ID4。

查询

filterGemstones()方法返回用户要将产品过滤到的宝石。使用以下查询,我得到零记录,但是如果我删除HAVING Count(DISTINCT p.product_id) = 2,我得到的产品ID是4、5

two muppets

  • HQL:

    createQuery("select p.productId from Product p JOIN p.gemstones g where g in :gemstones group by p having count (distinct p) =" +  filterGemstones().size() ).setParameter("gemstones",filterGemstones());
    
  • 由休眠生成的SQL:

    SELECT p.product_id 
    FROM   product p 
    INNER JOIN gemstone_product gp 
           ON p.product_id = gp.product_id 
    INNER JOIN gemstone g 
           ON gp.gemstone_id = g.gemstone_id 
    WHERE  g.gemstone_id IN ( 51, 46 ) 
    GROUP  BY p.product_id 
    HAVING Count(DISTINCT p.product_id) = 2 
    

产品类别:

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "product_id")
    private long productId;

    @ManyToMany()
    @JoinTable(
            name = "gemstone_product",
            joinColumns = {@JoinColumn(name = "product_id")},
            inverseJoinColumns = {@JoinColumn(name = "gemstone_id")}
    )
    private Set<Gemstone> gemstones = new HashSet<>(0);

// setters and getters
}

宝石类:

@Entity
@Table(name = "gemstone")
public class Gemstone {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "gemstone_id")
    private long gemstoneId;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "gemstone_product",
            joinColumns = {@JoinColumn(name = "gemstone_id")},
            inverseJoinColumns = {@JoinColumn(name = "product_id")}
    )
    private Set<Product> products = new HashSet<>(0);

// setters and getters
}

1 个答案:

答案 0 :(得分:0)

实际上,我们在这里需要的SQL查询非常简单:

SELECT t1.product_id 
FROM gemstone_product AS t1 
WHERE (t1.gemstone_id IN ?1 )  # (51, 46)
GROUP BY  t1.product_id  
HAVING (COUNT(t1.gemstone_id) = ?2) # 2 - # of items

使用JPA创建它并不容易,但可以使用FluentJPA(产生上面的查询)来完成,这有点令人沮丧:

public List<Integer> getProductsContainingAllStones(List<Long> gemstoneIds) {
    int count = gemstoneIds.size();

    FluentQuery query = FluentJPA.SQL((Gemstone gemstone,
                                       JoinTable<Gemstone, Product> gemstoneProduct) -> {

        discardSQL(gemstoneProduct.joinBy(gemstone.getProducts()));

        long productId = gemstoneProduct.getInverseJoined().getProductId();
        long gemstoneId = gemstoneProduct.getJoined().getGemstoneId();

        SELECT(productId);
        FROM(gemstoneProduct);
        WHERE(gemstoneIds.contains(gemstoneId));
        GROUP(BY(productId));
        HAVING(COUNT(gemstoneId) == count);
    });
    return query.createQuery(em).getResultList();
}

有关其工作原理的更多详细信息,请参见here