Friday, May 6, 2011

How can I add an element to a lazily-loaded collection in Hibernate without causing the collection to load?

What it says on the tin; I want to modify a collection in Hibernate without forcing the collection to load, since it is a large volume of data (~100,000 records, monotonically increasing).

Right now, I add an element to this list by calling getEvents ().add (newEvent) which, of course, causes events to be populated.

Here's the mapping:

<bag name = "events" inverse = "true" cascade = "all-delete-orphan"
 order-by = "event_date desc" lazy = "true">
  <key>
<column name = "document_id" length = "64" not-null = "true" />
  </key>
  <one-to-many class = "EventValue" />
</bag>

How should I be doing this?

From stackoverflow
  • One way to accomplish this would be to create a bidirectional association between the parent object (let's call it Parent) and the Event and configure your hibernate mappings such that the relationship is managed by Event.

    To accomplish this, your Hibernate mappings would look something like:

    <class name="Parent"...>
        ...
        <bag name="events" lazy="true" inverse="true"...>...</bag>
        ...
    </class>
    
    <class name="Event"...> 
        <many-to-one name="parent">
        ...
    </class>
    

    And your code would look something:

    myEvent.setParent(parentObject);
    eventDao.save(myEvent);
    

    Hope this helps. Good luck.

    Chris R : What side effects does that have in terms of working with the object, otherwise?
    blahspam : It really depends on how and when you are using the results of Parent.getEvents(). You may be required to re-fetch the Parent and/or expire it from the cache... but in most typical cases you won't need to do anything special and it will "just work"
  • Hibernate only lazy loads the proxied object (the Events) when it encounters a getter. You could try using a public field reference instead of the getter for Events eg.

    bean.events.add()
    

    rather than

    bean.getEvents().add()
    
  • Just insert the Event.

    for example :

    @Entity
    public Document
    {
        @ManyToOne
        Set<Event> events;
    
        public void addEvent( Event event )
        {
         events.add( event )
        }
    
    }
    
    
    @Entity
    public Event
    {
        @id
        private long id;
    
        @OneToMany
        private Document  doc;
    
        ....
    }
    

    Option that may read all of the events:

    document.add( event );
    update( document );
    

    Option that wouldn't touch the collection:

        event = new Event();
        event.setDocument( document );
        insert( event );
    

    Then when you call document.getEvents() it would query and get the new event also. The only issue is if the collection has already been read and then you insert the event by option 2. In that case the getEvents() would not include the new event since the collection has already been read.

    ccclark : Basically what blahspam was said.

0 comments:

Post a Comment