如何使用hibernate和jpa获取oneToMany懒惰关系

时间:2018-01-31 11:35:38

标签: hibernate jpa fetch jpql

问题:hibernate忽略了我在查询中输入的JOIN FETCH。我的目的是从oneToMany关系中检索product_item元素,该关系已设置为lazy但不会发生这种情况。

这是我正在尝试运行的查询:

em.createQuery("SELECT DISTINCT e " +
            "FROM ereturn e, " +
            "user shipper " +
            "JOIN FETCH product_item pi on pi.ereturn.id = e.id " +
            "JOIN FETCH product_definition pd on pi.product.id = pd.id " +
            "WHERE " +
            "shipper.id = e.shipper.id " +
            "AND e.scanDateTime IS NOT NULL " +
            "AND e.status = 'RECEIVED'").getResultList()

这是查询执行计划:

Hibernate: 
select
    distinct ereturn0_.id as id1_1_,
    ereturn0_.barcode as barcode2_1_,
    ereturn0_.carrier as carrier27_1_,
    ereturn0_.consignee as consign28_1_,
    ereturn0_.consigneeFirstName as consigne3_1_,
    ereturn0_.consigneeLastName as consigne4_1_,
    ereturn0_.creationtime as creation5_1_,
    ereturn0_.disabled as disabled6_1_,
    ereturn0_.dispatchedDate as dispatch7_1_,
    ereturn0_.failedReturnPOBoxPrivateBag as failedRe8_1_,
    ereturn0_.globalCondition as globalCo9_1_,
    ereturn0_.globalId as globalI10_1_,
    ereturn0_.groupName as groupNa11_1_,
    ereturn0_.invoice as invoice12_1_,
    ereturn0_.notes as notes13_1_,
    ereturn0_.pickupDateTime as pickupD14_1_,
    ereturn0_.pickupDateTimeOffset as pickupD15_1_,
    ereturn0_.pieces as pieces16_1_,
    ereturn0_.processedByShipper as process17_1_,
    ereturn0_.reasonToReturn as reasonT18_1_,
    ereturn0_.returnAction as returnA19_1_,
    ereturn0_.returnMethod as returnM20_1_,
    ereturn0_.returned as returne21_1_,
    ereturn0_.rma as rma22_1_,
    ereturn0_.scanDateTime as scanDat23_1_,
    ereturn0_.shipper as shipper29_1_,
    ereturn0_.status as status24_1_,
    ereturn0_.trackingNumber as trackin25_1_,
    ereturn0_.weight as weight26_1_ 
from
    ereturn ereturn0_ cross 
join
    user user1_ 
inner join
    product_item productite2_ 
        on (
            productite2_.ereturn=ereturn0_.id
        ) 
inner join
    product_definition productdef3_ 
        on (
            productite2_.product=productdef3_.id
        ) 
where
    user1_.id=ereturn0_.shipper 
    and (
        ereturn0_.scanDateTime is not null
    ) 
    and ereturn0_.status='RECEIVED'

执行查询但未获取ereturn.productItems因此json序列化会抱怨。

这些是我的课程:

public class Ereturn {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "shipper")
private User shipper = new User("", UserType.SHIPPER);
@ManyToOne
@JoinColumn(name = "consignee")
private User consignee;
@ManyToOne
@JoinColumn(name = "carrier")
private User carrier = new User("", UserType.CARRIER);
@JsonManagedReference(value="ereturn-parcel")
@OneToMany(mappedBy = "ereturn", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Parcel> parcels = new ArrayList<>();
@JsonManagedReference(value="ereturn-productItems")
@OneToMany(mappedBy = "ereturn", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<ProductItem> productItems = new ArrayList<>();
...
}

public class ProductItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name  = "product")
private ProductDefinition product;
@JsonBackReference(value="ereturn-productItems")
@ManyToOne
@JoinColumn(name = "ereturn")
private Ereturn ereturn;
...
}

public class ProductDefinition {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "shipper")
private User shipper;
@JsonIgnore
@OneToMany(mappedBy = "product", cascade = CascadeType.REFRESH)
private List<ProductItem> productItems = new ArrayList<>();
...
}

public class User implements SecurityContext {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JsonIgnore
@OneToMany(mappedBy = "shipper", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<ProductDefinition> productDefinitions = new HashSet<>();
@JsonIgnore
@OneToMany(mappedBy = "shipper", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Ereturn> ereturns = new HashSet<>(); // Client process ereturn to finish it
@JsonIgnore
@OneToMany(mappedBy = "shipper", cascade = CascadeType.ALL)
private Set<Contract> contracts = new HashSet<>();
private Boolean disabled = Boolean.FALSE;
...
}

问题1:为什么查询没有从product_item表中提取元素?

问题2:上面的查询返回的元素数量与数据库返回的行数相同,而不是ereturn分组。那是为什么?

1 个答案:

答案 0 :(得分:1)

我相信具有JOIN FETCH条件的ON不能在Hibernate上获取实体。在Hibernate文档或Internet上的示例中找不到这种用法。

要使FETCH工作,您需要使用两个实体之间的关系,并使用JOIN FETCH而不使用ON条件,例如:

SELECT e FROM eReturn e
JOIN FETCH e.productItens 

请记住要not use the fetched alias应用WHERE条件。