如何使用Hibernate和JPA来获取oneToMany惰性关系

How to fetch a oneToMany lazy relationship using hibernate and jpa

问题:hibernate状态忽略了我在查询中输入的JOIN FETCH。我的意图是从已设置为惰性的oneToMany关系中检索product_item元素,但这没有发生。

这是我要运行的查询:

1
2
3
4
5
6
7
8
9
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()

这是查询执行计划:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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序列化。

这些是我的课程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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:上面的查询返回的元素数量与数据库返回的行数相同,而不是通过返回进行分组。为什么会这样?


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

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

1
2
SELECT e FROM eReturn e
JOIN FETCH e.productItens

请记住不要使用获取的别名来应用WHERE条件。