JPA : Add and remove operations on lazily initialized collection behaviour ?

Posted by Albert Kam on Stack Overflow See other posts from Stack Overflow or by Albert Kam
Published on 2011-03-10T07:09:12Z Indexed on 2011/03/10 8:10 UTC
Read the original article Hit count: 290

Filed under:
|
|

Hello, im currently trying out JPA 2 and using Hibernate 3.6.x as the engine.

I have an entity of ReceivingGood that contains a List of ReceivingGoodDetail, and has a bidirectional relation. Some related codes for each entity follows :


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);
}

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

ReceivingGoodDetail.java :

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

In my experiements with both of these entities, both adding the detail to the receivingGood's collection, and even removing the detail from the receivingGood's collection, will trigger a query to fill the collection before doing the add or remove.

This assumption is based on my experiments that i will paste below.

My concern is that : is it ok to do changes on only a little bit of records on the collection, and the engine has to query all of the details belonging to the collection ?

What if the collection would have to be filled with 1000 records when i just want to edit a single record ?

Here are my experiments with the output as the comment above each method :

/*
    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());
}

Please share your experience on this matter !

Thank you !

© Stack Overflow or respective owner

Related posts about hibernate

Related posts about jpa