添加和删​​除懒惰初始化集合行为的操作?

时间:2011-03-10 07:09:13

标签: hibernate jpa jpa-2.0

我目前正在试用JPA 2并使用Hibernate 3.6.x作为引擎。

我有一个ReceivingGood实体,它包含一个ReceivingGoodDetail列表,并且具有双向关系。每个实体的一些相关代码如下:


ReceivingGood.java

@OneToMany(mappedBy="receivingGood",  
        targetEntity=ReceivingGoodDetail.class, 
        fetch=FetchType.LAZY, cascade = CascadeType.ALL)
private List<ReceivingGoodDetail> details = new ArrayList<ReceivingGoodDetail>();

public void addReceivingGoodDetail(ReceivingGoodDetail receivingGoodDetail) {
    receivingGoodDetail.setReceivingGood(this);
}

void internalAddReceivingGoodDetail(ReceivingGoodDetail receivingGoodDetail) {
    this.details.add(receivingGoodDetail);
}

public void removeReceivingGoodDetail(ReceivingGoodDetail receivingGoodDetail) {
    receivingGoodDetail.setReceivingGood(null);
}

void internalRemoveReceivingGoodDetail(ReceivingGoodDetail receivingGoodDetail) {
    this.details.remove(receivingGoodDetail);
}

ReceivingGoodDetail.java:

@ManyToOne
@JoinColumn(name = "receivinggood_id")
private ReceivingGood receivingGood;

public void setReceivingGood(ReceivingGood receivingGood) {
    if (this.receivingGood != null) { this.receivingGood.internalRemoveReceivingGoodDetail(this); }
    this.receivingGood = receivingGood;
    if (receivingGood != null) { receivingGood.internalAddReceivingGoodDetail(this); }
}

在我使用这两个实体的经验中,既将细节添加到receivingGood的集合,甚至从receivingGood的集合中删除细节,也会在执行添加或删除之前触发查询以填充集合。

这个假设是基于我将在下面粘贴的实验。

我担心的是:只对集合上的一些记录进行更改是否可以,引擎必须查询属于该集合的所有细节?

当我只想编辑单个记录时,如果要收集1000条记录,该怎么办?

以下是我使用输出作为每个方法上方注释的实验:

/*
    Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, ... too long
    Hibernate: select receivingg0_.id as id10_20_, receivingg0_.creationDate as creation2_10_20_, ... too long
    removing existing detail from lazy collection
    Hibernate: select details0_.receivinggood_id as receivi13_9_8_, details0_.id as id8_, details0_.id as id10_7_, details0_.creationDate as creation2_10_7_, details0_.modificationDate as modifica3_10_7_, details0_.usercreate_id as usercreate10_10_7_, details0_.usermodify_id as usermodify11_10_7_, details0_.version as version10_7_, details0_.buyQuantity as buyQuant5_10_7_, details0_.buyUnit as buyUnit10_7_, details0_.internalQuantity as internal7_10_7_, details0_.internalUnit as internal8_10_7_, details0_.product_id as product12_10_7_, details0_.receivinggood_id as receivi13_10_7_, details0_.supplierLotNumber as supplier9_10_7_, user1_.id as id2_0_, user1_.creationDate as creation2_2_0_, user1_.modificationDate as modifica3_2_0_, user1_.usercreate_id as usercreate6_2_0_, user1_.usermodify_id as usermodify7_2_0_, user1_.version as version2_0_, user1_.name as name2_0_, user2_.id as id2_1_, user2_.creationDate as creation2_2_1_, user2_.modificationDate as modifica3_2_1_, user2_.usercreate_id as usercreate6_2_1_, user2_.usermodify_id as usermodify7_2_1_, user2_.version as version2_1_, user2_.name as name2_1_, user3_.id as id2_2_, user3_.creationDate as creation2_2_2_, user3_.modificationDate as modifica3_2_2_, user3_.usercreate_id as usercreate6_2_2_, user3_.usermodify_id as usermodify7_2_2_, user3_.version as version2_2_, user3_.name as name2_2_, user4_.id as id2_3_, user4_.creationDate as creation2_2_3_, user4_.modificationDate as modifica3_2_3_, user4_.usercreate_id as usercreate6_2_3_, user4_.usermodify_id as usermodify7_2_3_, user4_.version as version2_3_, user4_.name as name2_3_, product5_.id as id0_4_, product5_.creationDate as creation2_0_4_, product5_.modificationDate as modifica3_0_4_, product5_.usercreate_id as usercreate7_0_4_, product5_.usermodify_id as usermodify8_0_4_, product5_.version as version0_4_, product5_.code as code0_4_, product5_.name as name0_4_, user6_.id as id2_5_, user6_.creationDate as creation2_2_5_, user6_.modificationDate as modifica3_2_5_, user6_.usercreate_id as usercreate6_2_5_, user6_.usermodify_id as usermodify7_2_5_, user6_.version as version2_5_, user6_.name as name2_5_, user7_.id as id2_6_, user7_.creationDate as creation2_2_6_, user7_.modificationDate as modifica3_2_6_, user7_.usercreate_id as usercreate6_2_6_, user7_.usermodify_id as usermodify7_2_6_, user7_.version as version2_6_, user7_.name as name2_6_ from ReceivingGoodDetail details0_ left outer join COMMON_USER user1_ on details0_.usercreate_id=user1_.id left outer join COMMON_USER user2_ on user1_.usercreate_id=user2_.id left outer join COMMON_USER user3_ on user2_.usermodify_id=user3_.id left outer join COMMON_USER user4_ on details0_.usermodify_id=user4_.id left outer join Product product5_ on details0_.product_id=product5_.id left outer join COMMON_USER user6_ on product5_.usercreate_id=user6_.id left outer join COMMON_USER user7_ on product5_.usermodify_id=user7_.id where details0_.receivinggood_id=?
    after removing try selecting the size : 4
    after removing, now flushing
    Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?, version=?, purchaseorder_id=?, supplier_id=?, transactionDate=?, transactionNumber=?, transactionType=?, transactionYearMonth=?, warehouse_id=? where id=? and version=?
    Hibernate: update ReceivingGoodDetail set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?, version=?, buyQuantity=?, buyUnit=?, internalQuantity=?, internalUnit=?, product_id=?, receivinggood_id=?, supplierLotNumber=? where id=? and version=?
    detail size : 4
    */
public void removeFromLazyCollection() {
    String headerId = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, headerId);

    // get existing detail
    ReceivingGoodDetail detail = em.find(ReceivingGoodDetail.class, "323fb0e7-9bb2-48dc-bc07-5ff32f30e131");
    detail.setInternalUnit("MCB");
    System.out.println("removing existing detail from lazy collection");
    receivingGood.removeReceivingGoodDetail(detail);
    System.out.println("after removing try selecting the size : " + receivingGood.getDetails().size());
    System.out.println("after removing, now flushing");
    em.flush();
    System.out.println("detail size : " + receivingGood.getDetails().size());
}

/*
    Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_,  ... too long
    Hibernate: select receivingg0_.id as id10_20_, receivingg0_.creationDate as creation2_10_20_,  ... too long
    adding existing detail into lazy collection
    Hibernate: select details0_.receivinggood_id as receivi13_9_8_, details0_.id as id8_, details0_.id as id10_7_, details0_.creationDate as creation2_10_7_, details0_.modificationDate as modifica3_10_7_, details0_.usercreate_id as usercreate10_10_7_, details0_.usermodify_id as usermodify11_10_7_, details0_.version as version10_7_, details0_.buyQuantity as buyQuant5_10_7_, details0_.buyUnit as buyUnit10_7_, details0_.internalQuantity as internal7_10_7_, details0_.internalUnit as internal8_10_7_, details0_.product_id as product12_10_7_, details0_.receivinggood_id as receivi13_10_7_, details0_.supplierLotNumber as supplier9_10_7_, user1_.id as id2_0_, user1_.creationDate as creation2_2_0_, user1_.modificationDate as modifica3_2_0_, user1_.usercreate_id as usercreate6_2_0_, user1_.usermodify_id as usermodify7_2_0_, user1_.version as version2_0_, user1_.name as name2_0_, user2_.id as id2_1_, user2_.creationDate as creation2_2_1_, user2_.modificationDate as modifica3_2_1_, user2_.usercreate_id as usercreate6_2_1_, user2_.usermodify_id as usermodify7_2_1_, user2_.version as version2_1_, user2_.name as name2_1_, user3_.id as id2_2_, user3_.creationDate as creation2_2_2_, user3_.modificationDate as modifica3_2_2_, user3_.usercreate_id as usercreate6_2_2_, user3_.usermodify_id as usermodify7_2_2_, user3_.version as version2_2_, user3_.name as name2_2_, user4_.id as id2_3_, user4_.creationDate as creation2_2_3_, user4_.modificationDate as modifica3_2_3_, user4_.usercreate_id as usercreate6_2_3_, user4_.usermodify_id as usermodify7_2_3_, user4_.version as version2_3_, user4_.name as name2_3_, product5_.id as id0_4_, product5_.creationDate as creation2_0_4_, product5_.modificationDate as modifica3_0_4_, product5_.usercreate_id as usercreate7_0_4_, product5_.usermodify_id as usermodify8_0_4_, product5_.version as version0_4_, product5_.code as code0_4_, product5_.name as name0_4_, user6_.id as id2_5_, user6_.creationDate as creation2_2_5_, user6_.modificationDate as modifica3_2_5_, user6_.usercreate_id as usercreate6_2_5_, user6_.usermodify_id as usermodify7_2_5_, user6_.version as version2_5_, user6_.name as name2_5_, user7_.id as id2_6_, user7_.creationDate as creation2_2_6_, user7_.modificationDate as modifica3_2_6_, user7_.usercreate_id as usercreate6_2_6_, user7_.usermodify_id as usermodify7_2_6_, user7_.version as version2_6_, user7_.name as name2_6_ from ReceivingGoodDetail details0_ left outer join COMMON_USER user1_ on details0_.usercreate_id=user1_.id left outer join COMMON_USER user2_ on user1_.usercreate_id=user2_.id left outer join COMMON_USER user3_ on user2_.usermodify_id=user3_.id left outer join COMMON_USER user4_ on details0_.usermodify_id=user4_.id left outer join Product product5_ on details0_.product_id=product5_.id left outer join COMMON_USER user6_ on product5_.usercreate_id=user6_.id left outer join COMMON_USER user7_ on product5_.usermodify_id=user7_.id where details0_.receivinggood_id=?
    after adding try selecting the size : 5
    after adding, now flushing
    Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?, version=?, purchaseorder_id=?, supplier_id=?, transactionDate=?, transactionNumber=?, transactionType=?, transactionYearMonth=?, warehouse_id=? where id=? and version=?
    detail size : 5
    */
public void editLazyCollection() {
    String headerId = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, headerId);

    // get existing detail
    ReceivingGoodDetail detail = em.find(ReceivingGoodDetail.class, "323fb0e7-9bb2-48dc-bc07-5ff32f30e131");
    detail.setInternalUnit("MCB");
    System.out.println("adding existing detail into lazy collection");
    receivingGood.addReceivingGoodDetail(detail);
    System.out.println("after adding try selecting the size : " + receivingGood.getDetails().size());
    System.out.println("after adding, now flushing");
    em.flush();
    System.out.println("detail size : " + receivingGood.getDetails().size());
}

请分享您对此事的经验!

谢谢!

1 个答案:

答案 0 :(得分:4)

  

在我使用这两个实体的经验中,既将细节添加到receivingGood的集合,甚至从receivingGood的集合中删除细节,也会在执行添加或删除之前触发查询以填充集合。

如果您正在“触摸”该集合,Hibernate知道您想要访问这些元素,它将触发“延迟初始化”。正如您所看到的,Hibernate为集合中的每个项目发出一个查询。您可以通过设置批量大小来避免这种情况:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-fetching-batch

  

当我只想编辑单个记录时,如果要收集1000条记录,该怎么办?

不要处理收藏品。您正在使用“mappedBy”,这意味着关系的拥有部分是“一个”部分,而不是“很多”部分。因此,只需将ReceivingGoodDetail中的ReceivingGood设置为null即可。

还有一件事:我认为ReceivingGoodDetail是ReceivingGood的一部分。我相信在这种情况下,Set比List更合适。