gpt4 book ai didi

多对多关系中的 JPA 条件查询

转载 作者:行者123 更新时间:2023-12-04 21:17:23 24 4
gpt4 key购买 nike

我在 EclipseLink 2.3.2 中使用 JPA 2.0,其中产品及其颜色之间存在多对多关系。一种产品可以有多种颜色,一种颜色可以与多种产品相关联。这种关系在数据库中由三个表表示。

  • 产品
  • prod_colour(连接表)
  • 颜色
  • prod_colour表有两个引用列 prod_idcolour_id来自其相关的父表 productcolour分别。

    很明显,实体类 Product有一组颜色 - java.util.Set<Colour>名为 colourSet .

    实体类 Colour有一套产品 - java.util.Set<Product>名为 productSet .

    我需要从 colour 获取颜色列表表 基于 prodId提供哪个 不是 匹配 prod_colour 中的颜色 table 。

    对应的 JPQL 如下所示。

    FROM Colour colour 
    WHERE colour.colourId
    NOT IN(
    SELECT colours.colourId
    FROM Product product
    INNER JOIN product.colourSet colours
    WHERE product.prodId=:id)
    ORDER BY colour.colourId DESC

    它生成以下 SQL 语句。

    SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
    FROM projectdb.colour t0
    WHERE t0.colour_id
    NOT IN (
    SELECT DISTINCT t1.colour_id
    FROM prod_colour t3, projectdb.product t2, projectdb.colour t1
    WHERE ((t2.prod_id = ?)
    AND ((t3.prod_id = t2.prod_id)
    AND (t1.colour_id = t3.colour_id))))
    ORDER BY t0.colour_id DESC

    因为这又是一个运行时查询,所以最好有一个条件查询。我没有洞察力在这种复杂的关系中制造标准查询。

    到目前为止,我有以下查询,它与前面的 JPQL 完全无关。
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Colour>criteriaQuery=criteriaBuilder.createQuery(Colour.class);
    Metamodel metamodel = entityManager.getMetamodel();
    EntityType<Colour> entityType = metamodel.entity(Colour.class);
    Root<Colour> root = criteriaQuery.from(entityType);
    SetJoin<Colour, Product> join = root.join(Colour_.productSet, JoinType.INNER);
    ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
    criteriaQuery.where(criteriaBuilder.equal(join.get(Product_.prodId), parameterExpression));

    TypedQuery<Colour> typedQuery = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, prodId);
    List<Colour> list=typedQuery.getResultList();

    如何编写与给定 JPQL 对应的条件查询?

    编辑:

    此条件查询:
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createQuery(Tuple.class);
    Metamodel metamodel = entityManager.getMetamodel();
    EntityType<Colour> entityType = metamodel.entity(Colour.class);
    Root<Colour> root = criteriaQuery.from(entityType);
    criteriaQuery.multiselect(root.get(Colour_.colourId));
    SetJoin<Colour, Product> join = root.join(Colour_.productSet, JoinType.INNER);
    ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
    criteriaQuery.where(criteriaBuilder.equal(join.get(Product_.prodId), parameterExpression));

    TypedQuery<Tuple> typedQuery = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, prodId);
    List<Tuple> list = typedQuery.getResultList();

    进而产生以下 SQL 查询。

    SELECT t0.colour_id 
    FROM projectdb.colour t0, prod_colour t2, projectdb.product t1
    WHERE ((t1.prod_id = 1)
    AND ((t2.colour_id = t0.colour_id)
    AND (t1.prod_id = t2.prod_id))))

    如何将此查询与子查询相关联,以便生成以下 SQL 查询?

    SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
    FROM projectdb.colour t0
    WHERE t0.colour_id
    NOT IN (
    SELECT t0.colour_id
    FROM projectdb.colour t0, prod_colour t2, projectdb.product t1
    WHERE ((t1.prod_id = 1)
    AND ((t2.colour_id = t0.colour_id)
    AND (t1.prod_id = t2.prod_id))))
    ORDER BY t0.colour_id DESC

    编辑:

    以下条件查询以及 NOT EXISTS()作品。
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Colour>criteriaQuery=criteriaBuilder.createQuery(Colour.class);
    Metamodel metamodel = entityManager.getMetamodel();
    EntityType<Colour> entityType = metamodel.entity(Colour.class);
    Root<Colour> root = criteriaQuery.from(entityType);
    criteriaQuery.select(root);
    Subquery<Long>subquery=criteriaQuery.subquery(Long.class);
    Root<Product> subRoot = subquery.from(Product.class);
    subquery.select(root.get(Colour_.colourId));
    Predicate paramPredicate = criteriaBuilder.equal(subRoot.get(Product_.prodId), prodId);
    Predicate correlatePredicate = criteriaBuilder.equal(root.get(Colour_.productSet), subRoot);
    subquery.where(criteriaBuilder.and(paramPredicate, correlatePredicate));
    criteriaQuery.where(criteriaBuilder.exists(subquery).not());
    criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Colour_.colourId)));

    TypedQuery<Colour> typedQuery = entityManager.createQuery(criteriaQuery);
    List<Colour>list= typedQuery.getResultList();

    但是,它会生成带有不必要/额外/冗余连接的 SQL 查询,如下所示(它返回所需的结果集,尽管它看起来是这样)。

    SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
    FROM projectdb.colour t0
    WHERE
    NOT (EXISTS (
    SELECT t0.colour_id
    FROM prod_colour t3, projectdb.product t2, projectdb.product t1
    WHERE (((t1.prod_id = 1)
    AND (t1.prod_id = t2.prod_id))
    AND ((t3.colour_id = t0.colour_id)
    AND (t2.prod_id = t3.prod_id)))))
    ORDER BY t0.colour_id DESC

    这应该就像,

    SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
    FROM projectdb.colour t0
    WHERE
    NOT (EXISTS (
    SELECT t0.colour_id
    FROM prod_colour t3, projectdb.product t2
    WHERE (((t2.prod_id = 1))
    AND ((t3.colour_id = t0.colour_id)
    AND (t2.prod_id = t3.prod_id)))))
    ORDER BY t0.colour_id DESC

    有没有办法使用 NOT IN() 进行子查询?子句而不是 NOT EXISTS()并摆脱这种多余的连接?

    此查询产生的冗余连接已报告为 bug .

    最佳答案

    以下是关于NOT IN()的条件查询(然而,我更喜欢 NOT EXISTS() 而不是 NOT IN() )。

    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Colour>criteriaQuery=criteriaBuilder.createQuery(Colour.class);
    Metamodel metamodel = entityManager.getMetamodel();
    EntityType<Colour> entityType = metamodel.entity(Colour.class);
    Root<Colour> root = criteriaQuery.from(entityType);
    criteriaQuery.select(root);

    Subquery<Long>subquery=criteriaQuery.subquery(Long.class);
    Root<Product> subRoot = subquery.from(Product.class);
    subquery.select(root.get(Colour_.colourId));

    Predicate paramPredicate = criteriaBuilder.equal(subRoot.get(Product_.prodId), prodId);
    Predicate correlatePredicate = criteriaBuilder.equal(root.get(Colour_.productSet), subRoot);

    subquery.where(criteriaBuilder.and(paramPredicate, correlatePredicate));
    criteriaQuery.where(criteriaBuilder.in(root.get(Colour_.colourId)).value(subquery).not());
    criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Colour_.colourId)));

    TypedQuery<Colour> typedQuery = entityManager.createQuery(criteriaQuery);
    List<Colour> list=typedQuery.getResultList();

    这将产生以下 SQL 查询。

    SELECT t0.colour_id, t0.colour_hex, t0.colour_name 
    FROM projectdb.colour t0
    WHERE NOT
    (t0.colour_id IN (
    SELECT t0.colour_id
    FROM prod_colour t3, projectdb.product t2, projectdb.product t1
    WHERE (((t1.prod_id = ?)
    AND (t1.prod_id = t2.prod_id))
    AND ((t3.colour_id = t0.colour_id)
    AND (t2.prod_id = t3.prod_id)))))
    ORDER BY t0.colour_id DESC

    此查询返回所需的结果集。但是,它会产生一个冗余连接,可以看出,但这似乎是 bug .

    编辑:

    尝试 the same query在 Hibernate 上,编写此条件查询的方式看起来不正确。连接和子查询的组合会产生正确的 SQL 查询。
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery<Colour>criteriaQuery=criteriaBuilder.createQuery(Colour.class);
    Metamodel metamodel = entityManager.getMetamodel();
    EntityType<Colour> entityType = metamodel.entity(Colour.class);
    Root<Colour> root = criteriaQuery.from(entityType);
    criteriaQuery.select(root);

    Subquery<Long>subquery=criteriaQuery.subquery(Long.class);
    Root<Colour> subRoot = subquery.from(Colour.class);
    subquery.select(subRoot.get(Colour_.colourId));
    SetJoin<Colour, Product> join = subRoot.join(Colour_.productSet, JoinType.INNER);

    ParameterExpression<Long> parameterExpression=criteriaBuilder.parameter(Long.class);
    criteriaQuery.where(criteriaBuilder.in(root.get(Colour_.colourId)).value(subquery).not());
    subquery.where(criteriaBuilder.equal(join.get(Product_.prodId), parameterExpression));
    criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Colour_.colourId)));

    TypedQuery<Colour> typedQuery = entityManager.createQuery(criteriaQuery);
    List<Colour> list = typedQuery.setParameter(parameterExpression, 1L).getResultList();

    这将产生以下 SQL 查询,该查询又将委托(delegate)给 MySQL。

    SELECT t0.colour_id, t0.colour_name, t0.colour_hex
    FROM projectdb.colour t0
    WHERE NOT (t0.colour_id IN
    (SELECT t1.colour_id
    FROM prod_colour t3, projectdb.product t2, projectdb.colour t1
    WHERE ((t2.prod_id = ?)
    AND ((t3.colour_id = t1.colour_id)
    AND (t2.prod_id = t3.prod_id)))))
    ORDER BY t0.colour_id DESC

    关于多对多关系中的 JPA 条件查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19830910/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com