JPA一对多连接表提供不正确的子记录

时间:2016-11-16 07:07:38

标签: java spring jpa criteriaquery

我正在使用Spring框架。我有两张桌子套餐&项目和关系是一个包有很多项目。表格设计类似于:

    @Entity
    @Table(name = "TB_PACKAGE")
    public class Packages implements Serializable{

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "PACKAGE_ID")
    private String packageId;

    @Valid
    @OneToMany(mappedBy = "packages", cascade = { CascadeType.ALL })
    private List<Item> item;

项目

    @Entity
    @Table(name = "TB_ITEM")
    public class Item implements Serializable{

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "ITEM_ID")
    private String itemId;

    @ManyToOne
    @JoinColumn(name="PACKAGE_ID")
    private Packages packages;

    @Transient
    private String packageId;

Sample records

这是我通过使用CriteriaBuilder来获取连接表的代码来获得这样的结果。

SQL:

    SELECT * FROM Packages p JOIN Item i ON p.packageId = i.packageId; 

爪哇:

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Packages> cq = cb.createQuery(Packages.class);
    Root<Packages> pRoot = cq.from(Packages.class);
    Join<Packages, Item> packagesItem = pRoot.join("item");
    List<Predicate> predicates = new ArrayList<Predicate>();

    if (StringUtils.isNotEmpty(itemName)) {
        predicates.add(cb.like(cb.lower(packagesItem.<String>get("itemName")), "%" + itemName.toLowerCase() + "%"));
    }

    Predicate[] predArray = new Predicate[predicates.size()];
    predicates.toArray(predArray);

    cq.where(predArray);
    cq.distinct(true);

    TypedQuery<Packages> query = em.createQuery(cq);

    return query.getResultList();

如果我输入'phone'作为我的参数,它假设应该记录为JSON:

   "packageId": "P1",
   "item": [
        {
          "itemId": "Item 1",
          "temName" "Phone"
        }
    ]

然而,这些包总是加载它的所有孩子:

   "packageId": "P1",
   "item": [
        {
          "itemId": "Item 1",
          "temName" "Phone"
        },
        {
          "itemId": "Item 2",
          "temName" "Laptop"
        },
        {
          "itemId": "Item 3",
          "temName" "Mouse"
        }
    ]

我已经尝试了一切:FetchType.Lazy,QueryDsl,Native Query,HQL等但仍然没有运气。有人有解决方案吗?

3 个答案:

答案 0 :(得分:0)

您的@OneToMany映射似乎不正确。 尝试更改

@Valid
@OneToMany(mappedBy = "items", cascade = { CascadeType.ALL })
private List<Item> item;

@Valid
@OneToMany(mappedBy = "packages", cascade = { CascadeType.ALL })
private List<Item> item;

完成映射后,您必须检查JOIN FETCH

答案 1 :(得分:0)

我认为问题出在JOIN上的SQL语法上。

  

INNER JOIN:当BOTH表中至少有一个匹配时返回所有行

     

LEFT JOIN:返回左表中的所有行,以及右表中匹配的行

     
    

有时它被称为LEFT OUTER JOIN

  
     

RIGHT JOIN:返回右表中的所有行,以及左表中匹配的行

     

FULL JOIN:当其中一个表中存在匹配时返回所有行

使用JOIN时,默认情况下,至少对于SQL Server和MySQL,与INNER JOIN等效。我认为您的底层lib / jar还将为您提供其他JOIN类型的类。

尝试指定INNER JOIN,或尝试WHERE。对我来说WHERE更清楚。

这个问题可能有所帮助:

Hibernate default joining for nullable many-to-one

答案 2 :(得分:0)

您需要的是JOIN FETCH而不是JOIN

Join<Packages, Item> packagesItem = pRoot.fetch("item");

作为JPQL

Select packages from Packages packages join fetch packages.item where packages.item.temName like '%'+itemName+'%';

how-to-properly-express-jpql-join-fetch-with-where-clause-as-jpa-2-criteriaq