-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 
Author Message
 Post subject: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Fri Mar 26, 2010 11:06 am 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
Hi I have tried to research this independently and I have tried the "solutions" other posts have recommended to no avail.

I have a parent child relationship where I cannot get the parent relationship to load lazily.

Code:
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DocumentCategoryModel.class, optional=false)
    @JoinColumn(name = "parent_id")
    @ForeignKey(name = "FK_CAT_PARENT")
    public DocumentCategory getParent() {
        return _parent;
    }


I have tried many variations on the above and nothing seems to work.
For instance i added:
Code:
    @LazyToOne(LazyToOneOption.PROXY)
    @Fetch(FetchMode.SELECT)

I tried it with and without optional=false and with optional=true on the @ManyToOne
I tried it with nullable=true and nullable=false on the @JoinColumn

There is a reverse OnToMany relationship and I completely removed that to see if that would work... and it didn't.

This relationship could be very deep, ie dozens of parents, and right now I have no way of stopping all the parents from getting loaded right up to the root of the relationship.

Does anyone have any suggestions?

Thanks
Bill


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Fri Mar 26, 2010 11:30 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Can you please show how your schema is created?
In particular it's is interesting me where parent_id field is mapped.
If it is mapped in the source class (you don't specify the name of your source entity)
or if it is mapped in the target class (target entity) DocumentCategoryModel.
(In ladder case Lazy cannot not work).


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Fri Mar 26, 2010 12:07 pm 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
I am not sure I understand the question.

In the case of DocumentCategoryModel is self referential.

We also have a DocumentModel class that refers to DocumentCategoryModel

In DocumentCategoryModel it is:
Code:
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DocumentCategoryModel.class, optional=false)
    @JoinColumn(name = "parent_id", nullable=false)
    @ForeignKey(name = "FK_CAT_PARENT")
    public DocumentCategory getParent() {
        return _parent;
    }


In DocumentModel it is:
Code:
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DocumentCategoryModel.class, optional=false)
    @JoinColumn(name = "parent_id")
    @ForeignKey(name = "FK_DOCCAT_DOC")
   public DocumentCategory getParent() {
       return _parent;
   }


In both cases they refer to the primary key on DocumentCategoryModel:
Code:
   @GeneratedValue(strategy = GenerationType.AUTO, generator="DocCatModelSeq")
   @SequenceGenerator(name="DocCatModelSeq",sequenceName="loftware.doc_cat_seq")
   @Id
   public Long getId(){
      return _id;
   }


I can ignore/remove DocumentModel completely and DocumentCategoryModel still eagerly fetches its parent.

To clarify, In both tables there is a parent_id column acting as a foreign key that refers to The DocumentCategoryModel

Is there another way of defining this relationship?

Why would Lazy init be impossible? You load the row, you see that its parent_id column is not null but lazy initialized, you put a lazy inititing proxy around the getter... not sure why this wouldn't work...


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Fri Mar 26, 2010 12:30 pm 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
Here is the full bi-directional relationship in the DocumentCategoryModel just in case its not clear.

In this case there is not difference between the target/source ... which is why the previous question is very confusing.

Code:
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DocumentCategoryModel.class, optional=false)
    @JoinColumn(name = "parent_id", nullable=false)
    @ForeignKey(name = "FK_CAT_PARENT")
    public DocumentCategory getParent() {
        return _parent;
    }

    @OneToMany(fetch=FetchType.LAZY, targetEntity = DocumentCategoryModel.class, mappedBy = "parent")
    @ForeignKey(name = "FK_CAT_PARENT")
    public Set<DocumentCategory> getChildCategories() {
        return _childCategories;
    }


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Mon Mar 29, 2010 8:52 am 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
bump... can I get any assistance?
Thanks


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Mon Mar 29, 2010 9:01 am 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
Does this require byte code instrumentation?


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Mon Mar 29, 2010 9:44 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Lazy Loading on a ManyToOne relation should work, also without using proxies due byte code instrumentation.
(at least in my environments it always works).
I had a problem with your mapping, as one time you specify
_parent and another time parent without leading underscore (mappedBy = "parent")).
Can you post the entire DocumentCategoryModel class with all relevant annotations?

How do you recognize that lazy loading isn't working as you excpect?


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Mon Mar 29, 2010 10:43 am 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
I went through and removed all the "_" from the private instance fields... I didn't think it would matter because hibernate has always used the property name from the getter and not the field name. Re-running the test with the field names matching the accessors didnt change the test outcome in any way.

Here is the updated class:

Code:
@Entity
@Table(name = "category", schema="loftware")
public final class DocumentCategoryModel extends AbstractAclIdentityObject<DocumentCategory,DocumentCategory> implements DocumentCategory {

    private static final long     serialVersionUID = -3045174825695348190L;

    private DocumentCategory      parent;
    private Set<DocumentCategory> childCategories = new HashSet<DocumentCategory>();
    private Set<Document>         childDocuments  = new HashSet<Document>();
   private Long               id;
   private SortedSet<DocumentCategoryAclEntry> aclEntries = new TreeSet<DocumentCategoryAclEntry>();
   private static int allPermissionsValue =  LoftwarePermission.READ.getMask() +
                                   LoftwarePermission.WRITE.getMask() +
                                   LoftwarePermission.CREATE.getMask() +
                                   LoftwarePermission.DELETE.getMask() +
                                   LoftwarePermission.ADMINISTRATION.getMask() +
                                   LoftwarePermission.APPROVE.getMask() +
                                   LoftwarePermission.PUBLISH.getMask() +
                                   LoftwarePermission.PRINT.getMask() +
                                   LoftwarePermission.LIST.getMask();

   @Override
   @GeneratedValue(strategy = GenerationType.AUTO, generator="DocCatModelSeq")
   @SequenceGenerator(name="DocCatModelSeq",sequenceName="loftware.doc_cat_seq")
   @Id
   public Long getId(){
      return id;
   }
   @Override
   public void setId(Long id){
      this.id = id;
   }
   
   @Override
   @Transient
   public int getAllPermissionsValue() {
      return allPermissionsValue;
   }
   
   @Override
   @Transient
   public Boolean isParentListable() {
      return false;
   }

    /**
     * {@inheritDoc}
     *
     */
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DocumentCategoryModel.class)
    @JoinColumn(name = "parent_id", nullable=true)
    @ForeignKey(name = "FK_CAT_PARENT")
    public DocumentCategory getParent() {
        return parent;
    }
    public void setParent(DocumentCategory parent) {
        this.parent = parent;
    }

    @OneToMany(fetch=FetchType.LAZY, targetEntity = DocumentCategoryModel.class, mappedBy = "parent")
    @ForeignKey(name = "FK_CAT_PARENT")
    public Set<DocumentCategory> getChildCategories() {
        return childCategories;
    }

    public void setChildCategories(Set<DocumentCategory> childCategories) {
        if (childCategories == null) {
            this.childCategories.clear();
        } else {
            this.childCategories = childCategories;
        }
    }


    public void setChildDocuments(Set<Document> childDocuments) {
        if (childDocuments == null) {
            this.childDocuments.clear();
        }else{
           this.childDocuments = childDocuments;
        }
    }
    @Override
    public void addChildCategory(DocumentCategory category) {
        if (category != null) {
            category.setParent(this);
            getChildCategories().add(category);
        }

    }

    @Override
    public void addChildDocument(Document document) {
        if (document != null) {
            document.setParent(this);
            getChildDocuments().add(document);
        }

    }

    @Override
    public void removeChildCategory(DocumentCategory category) {
        if (category != null && childCategories.contains(category)) {
            category.setParent(null);
            childCategories.remove(category);
        }
    }

    @Override
    public void removeChildDocument(Document document) {
        if (document != null && childDocuments.contains(document)) {
            document.setParent(null);
            childDocuments.remove(document);
        }

    }

    @OneToMany( fetch = FetchType.LAZY, mappedBy="parent", targetEntity = DocumentModel.class)
    @ForeignKey(name = "FK_DOCCAT_DOC")
    @Cascade(org.hibernate.annotations.CascadeType.ALL)
    public Set<Document> getChildDocuments() {
        return childDocuments;
    }

   @Override
   @OneToMany(fetch = FetchType.LAZY, mappedBy = "identityObject", targetEntity=DocumentCategoryAclEntryModel.class, cascade=CascadeType.PERSIST)
   @ForeignKey(name = "FK_DOCCAT_ACL_LIST")
   @Sort(type=SortType.NATURAL)
   public SortedSet<DocumentCategoryAclEntry> getAclEntries() {
      return aclEntries   ;
   }
   @Override
   public void addAclEntry(AclEntryObject<DocumentCategory, DocumentCategory, Long> aclEntry) {
      getAclEntries().add((DocumentCategoryAclEntry)aclEntry);
   }
   @Override
   public void removeAclEntry(AclEntryObject<DocumentCategory, DocumentCategory, Long> aclEntry) {
      SortedSet<DocumentCategoryAclEntry> acls = getAclEntries();
      if(acls.contains(aclEntry)) acls.remove(aclEntry);
   }
   public void setAclEntries(SortedSet<DocumentCategoryAclEntry> entries){
      this.aclEntries = entries;
   }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);

        builder.append("name", getName());

        return builder.toString();
    }

   @Override
   @Transient
   protected int getHashPrimary() {
      return 7;
   }

   @Override
   @Transient
   protected int getHashSecondary() {
      return 17;
   }

   @Override
   @Transient
   public Class<DocumentCategoryModel> getJavaType() {
      return DocumentCategoryModel.class;
   }


This is the test I'm running:
Code:
    @Test
    public void testGetDocument() throws Exception{
       setUser(20l);
       System.out.println("before");
       DocumentCategory cat = documentCategoryDao.get(60l);
       System.out.println("getting parent after this");
       cat.getParent();
       System.out.println("after");
    }


This is the resulting System.out output is:
Code:
before
Hibernate:
    select
        documentca0_.id as id124_0_,
        documentca0_.system as system124_0_,
        documentca0_.modified as modified124_0_,
        documentca0_.created as created124_0_,
        documentca0_.created_issuer as created5_124_0_,
        documentca0_.last_updated_issuer as last6_124_0_,
        documentca0_.fully_qualified_name as fully7_124_0_,
        documentca0_.entries_inheriting as entries8_124_0_,
        documentca0_.name as name124_0_,
        documentca0_.parent_id as parent10_124_0_
    from
        loftware.category documentca0_
    where
        documentca0_.id=?
Hibernate:
    select
        documentca0_.id as id124_0_,
        documentca0_.system as system124_0_,
        documentca0_.modified as modified124_0_,
        documentca0_.created as created124_0_,
        documentca0_.created_issuer as created5_124_0_,
        documentca0_.last_updated_issuer as last6_124_0_,
        documentca0_.fully_qualified_name as fully7_124_0_,
        documentca0_.entries_inheriting as entries8_124_0_,
        documentca0_.name as name124_0_,
        documentca0_.parent_id as parent10_124_0_
    from
        loftware.category documentca0_
    where
        documentca0_.id=?
getting parent after this
after


As you can see its pulling the parent as part of the original fetch in a separate query.
documentCategoryDao is doing a simple entityManager.find(class,id);
so there is nothing special going on there.


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Wed Mar 31, 2010 7:40 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Hi Bill,

I can imagine the cause could be that you declare the parent property
as interface (DocumentCategory) and not as direct reference to your entity class DocumentCategoryModel.

Please try to substitute

Code:
private DocumentCategory      parent;

public DocumentCategory getParent() {
        return parent;
    }





with

Code:
private DocumentCategoryModel      parent;

public DocumentCategoryModel getParent() {
        return parent;
    }



and let us know if it solves the problem.


Top
 Profile  
 
 Post subject: Re: Hibernate JPA Lazy Loading on ManyToOne not working
PostPosted: Wed Mar 31, 2010 1:04 pm 
Newbie

Joined: Fri Mar 26, 2010 10:51 am
Posts: 7
I found the problem.

The class was declared final. So obvious now....


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.