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

标签 java mysql spring hibernate

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

关系:
  • 产品多对多 gem

我正在尝试编写一个查询来获取具有 gem A、 gem B 和 gem C 等的产品。

用例:

如果用户请求 gem 为 51 和 46 的产品。查询应仅返回产品 ID 4。

查询:

filterGemstones() 方法返回用户想要过滤产品的 gem 。使用下面的查询我得到零条记录,但如果我删除 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());
    
  • 由 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 
    

产品类别:

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

gem 类别:

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

最佳答案

实际上我们需要的 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.join(gemstone, 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 .

关于java - HQL 或 SQL 查询从许多相关实体获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57486892/

相关文章:

java - 如何避免 Java 中的多个 If 语句?

java - 使用openssl解密用java加密的aes-gcm

java - 我只想在.jsp文件中写入jsp,jSTL

php - 如何使用 mysqli 设置排序规则?

javascript - 使用 XMLHttpRequest、PDO、JSON、PHP 和 JavaScript 从数据库中获取数据

javascript - Spring Boot 应用程序启动时 Gulp

java - 如何在android中使用后台服务获取经纬度?

mysql - 得到下一个 xx :30 time (the next half-past hour) after a specified time

spring boot oauth2.0 和 spring 安全 : How to grant permission(authorities) to user login via facebook or slack

java - 如何通过两个线程打印非重复元素?