简体   繁体   English

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

[英]HQL or SQL query to get data from many to many related entities

I am using spring with hibernate to store data in MySql database. 我正在使用spring和hibernate将数据存储在MySql数据库中。 I am trying to retrieve rows based on filters requested by the user. 我正在尝试根据用户请求的过滤器检索行。 I have the following tables/entities : Product and Gemstone 我有以下表格/实体:产品和宝石

Relations: 关系:
  • Product many2many Gemstone 产品many2许多宝石

I am trying to write a query to get products that have Gemstone A and Gemstone B and Gemstone C.. and so on. 我正在尝试编写查询以获取具有宝石A,宝石B和宝石C ..等的产品。

Use Case: 用例:

If user is asking for a product with gemstones 51 and 46. Query should only return product id 4. 如果用户要求使用宝石51和46的产品。查询应仅返回产品ID 4。

Query: 查询:

filterGemstones() method return the gemstone user wants to filter products to. filterGemstones()方法返回用户要将产品过滤到的宝石。 Using the below query I get zero records but if I remove HAVING Count(DISTINCT p.product_id) = 2 I get product id 4, 5 使用以下查询,我得到零记录,但是如果我删除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 generate by hibernate : 由休眠生成的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 

Product class: 产品类别:

 @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 } 

Gemstone class: 宝石类:

 @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 } 

Actually the SQL query that we need here is pretty simple: 实际上,我们这里需要的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

It's a bit frustrating that it's not easy to create it with JPA, but it can be done with FluentJPA (produces the query above): 使用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();
}

More details on how it works can be found here . 有关其工作原理的更多详细信息,请参见此处

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM