#1503 ✓resolved
ransom-briggs (at uiowa)

Nested OneToMany relationships with orphanRemoval fails to commit

Reported by ransom-briggs (at uiowa) | April 23rd, 2012 @ 10:00 PM | in 1.2.5 (closed)

If there are @OneToMany relationships nested more than one level deep - the removal of the first level causes the commit to fail with "collection owner not associated with session: models.Order.parts".

I have attached a failing test which illuminates the behavior and which I will reference here (I added a parts OneToMany association to Order to get the double nesting)

public class CustomerOrders extends Controller {

    public static void create() {
        Customer customer = new Customer("Foobar");
        
        Order order = new Order("Couch", 3);
        order.customer = customer;
        
        Part part = new Part();
        part.order = order;

        order.parts.add(part);

        customer.orders.add(order);
        customer.save();
        
        renderText(customer.id);
    }

    public static void update(Long id) {
        Customer customer = Customer.findById(id);
        customer.orders.remove(0); // remove an order which has parts
        customer.save();  // fails on flush as part of commit
    }

Basically this code returns false because it is called with the parts collection, which looks at the Order owner which has willbesaved set to false since it does not get saveAndCascaded in JPABase since saveAndCascade sets willbesaved only for the current values currently in the collection not those that have been removed. Then hibernate gets really confused and gives up on committing.

        @Override
        public boolean onCollectionRemove(Object collection, Serializable key) throws CallbackException {
            if (collection instanceof PersistentCollection) {
                Object o = ((PersistentCollection) collection).getOwner();
                if (o instanceof JPABase) {
                    return ((JPABase) o).willBeSaved;
                }
            } else {
                System.out.println("HOO: Case not handled !!!");
            }
            return super.onCollectionRemove(collection, key);
        }

Comments and changes to this ticket

  • ransom-briggs (at uiowa)

    ransom-briggs (at uiowa) April 25th, 2012 @ 04:15 PM

    Adding a pull request https://github.com/playframework/play/pull/506

    I had to do something hibernate specific - I grab the orphans out of the session for this collection and then saveAndCascade those as well so that they have willBeSaved set as well. Which might change the semantics of willBeSaved a bit, cause it should probably be willBeSyncedToDatabase instead.

  • Play Duck
  • Play Duck

    Play Duck May 6th, 2012 @ 12:21 PM

    (from [0427c136120f67b3930f451aebdea53687f7f67a]) Merge pull request #506 from ransombriggs/1503

    [#1503] Nested OneToMany relationships with orphanRemoval fails to commit https://github.com/playframework/play/commit/0427c136120f67b3930f45...

  • Play Duck

    Play Duck May 6th, 2012 @ 12:33 PM

    (from [55818cdcffa8937c7c837c04dc963ae4e32b39db]) Merge pull request #506 from ransombriggs/1503

    [#1503] Nested OneToMany relationships with orphanRemoval fails to commit https://github.com/playframework/play/commit/55818cdcffa8937c7c837c...

  • Nicolas Leroux

    Nicolas Leroux May 6th, 2012 @ 12:34 PM

    • State changed from “new” to “resolved”
    • Assigned user set to “Nicolas Leroux”
    • Milestone set to 1.2.5
    • Milestone order changed from “1105” to “0”
  • Chris Webb

    Chris Webb January 25th, 2014 @ 12:03 PM

    I'm seeing this exact same issue in the 1.3 branch. Was this patch included in the 1.3 branch as well?

  • ransom-briggs (at uiowa)

    ransom-briggs (at uiowa) February 19th, 2014 @ 09:26 PM

    Chris,

    Sorry for the late response, work has been crazy lately. I do not believe this was included in 1.3, I run a custom version of play and when I went from 1.2.7 to 1.3 I believe I had to merge it again.

    Ransom

  • Chris Webb

    Chris Webb April 27th, 2014 @ 09:54 PM

    Hi Ransom,

    I checked the 1.3 branch and and it looks like the patch has been included there (See https://github.com/playframework/play1/blob/1.3.x/framework/src/pla...) but it would be great if you could confirm.

    Certainly it appears like I'm seeing the same issue that you were trying to fix. I have nested OneToMany relationships, SubEvent (Event) -> Tasks -> TaskHelper, and with orphanRemoval=true set for the last relationship I get the "collection owner not associated with session" exception when I attempt to delete an Event. The only added complexity with my situation is I'm using joined sub-class inheritance with the top Event entity.

    27-04-14 21:04:38,650 [play-thread-2] ERROR play
    
    
    @6i3e6k39k
    Internal Server Error (500) for request DELETE /sub-events/3558?x-http-method-override=DELETE
    
    Execution exception (In /app/controllers/Application.java around line 920)  
    AssertionFailure occured : collection owner not associated with session: models.Task.helpers
    
    play.exceptions.JavaExecutionException: collection owner not associated with session: models.Task.helpers  
            at play.mvc.ActionInvoker.invoke(ActionInvoker.java:237)
            at Invocation.HTTP Request(Play!)
    Caused by: org.hibernate.AssertionFailure: collection owner not associated with session: models.Task.helpers  
            at org.hibernate.engine.internal.Collections.processDereferencedCollection(Collections.java:108)
            at org.hibernate.engine.internal.Collections.processUnreachableCollection(Collections.java:67)
            at org.hibernate.event.internal.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:266)
            at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:100)
            at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
            at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1214)
            at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:981)
            at play.db.jpa.JPABase._save(JPABase.java:39)
            at play.db.jpa.GenericModel.save(GenericModel.java:215)
            at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:192)
            at models.CommunityEvent_$$_javassist_19.save(CommunityEvent_$$_javassist_19.java)
            at controllers.Application.subEventDelete(Application.java:920)
            at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:557)
            at play.mvc.ActionInvoker.invoke(ActionInvoker.java:508)
            at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:484)
            at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:479)
            at play.mvc.ActionInvoker.invoke(ActionInvoker.java:161)
            ... 1 more
    

    This is really frustrating and my hibernate debugging is not great. Any help appreciated, thx

  • ransom-briggs (at uiowa)

    ransom-briggs (at uiowa) May 1st, 2014 @ 07:42 PM

    Chris,

    Sorry for the delayed response, but could you extract some code that shows this behavior? I run a patched version of play and was looking at what is difference and I am not entirely certain it will fix your problem, but if you attach an example app with this problem, I can see if it passes under my version. If my patched version fixes it, I would be glad to push up a pull request. (I just forget exactly what the patch I have in mine was solving as it has been a while)

    Thanks,
    Ransom

  • Chris Webb

    Chris Webb June 22nd, 2014 @ 06:47 AM

    • Tag changed from 1.2.4, hibernate to 1.2.4, 1.3.0, hibernate

    Hi Ransom,

    As well sorry for my delayed response.

    My Model hierarchy is the following:

    +---------+                                                  
    |         |                                                  
    |Community|                                                  
    |Event    +-----+                                            
    |         |     |                                            
    +---------+     |       +-----+        +----+        +------+
         1          +-----> |     |        |    |        |      |
         |                  |Event|1------*|Task|1------*|Task  |
         *          +-----> |     |        |    |        |Helper|
      +-----+       |       +-----+        +----+        |      |
      |     |       |                                    +------+
      |Sub  +-------+                                            
      |Event|                                                    
      |     |                                                    
      +-----+
    

    So in my Application.subEventDelete() controller action I have the following:

    // Remove the specified sub event.
    communityEvent.removeSubEvent(subEvent);
    
    // Reset the order index for the remaining sub events.
    for (int i=index; i < communityEvent.subEvents.size(); i++) {
        communityEvent.subEvents.get(i).orderIndex = i;
    }
    
    communityEvent.save();
    

    The CommunityEvent model is defined as:

    @Entity
    public class CommunityEvent extends Event {
    
        @OneToMany(mappedBy="communityEvent", cascade=CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval=true)
        @OrderBy("orderIndex")
        public List<SubEvent> subEvents = new ArrayList<SubEvent>();
    
        public void removeSubEvent(SubEvent subEvent) {
            if (subEvent != null) {
                this.subEvents.remove(subEvent);
                subEvent.communityEvent = null;
                subEvent.orderIndex = null;
            }
        }
    }
    

    The SubEvent model is defined as:

    @Entity
    @Table(uniqueConstraints = @UniqueConstraint(columnNames={"communityEvent_id", "orderIndex"}))
    public class SubEvent extends Event {
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        public CommunityEvent communityEvent;
    
        @Column(nullable=false)
        public Integer orderIndex;
    }
    

    The Event model is defined as:

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public abstract class Event extends Model {
        @OneToMany(mappedBy = "event", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
        @OrderBy("orderIndex")
        public List<Task> tasks = new ArrayList<Task>();
    }
    

    The Task model is defined as:

    @Entity
    @Table(uniqueConstraints = @UniqueConstraint(columnNames={"event_id", "orderIndex"}))
    public class Task extends Model {
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        public Event event;
    
        @Column(nullable=false)
        public int orderIndex;
    
        @OneToMany(mappedBy = "task", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
        public Set<TaskHelper> helpers = new HashSet<TaskHelper>();
    }
    

    The TaskHelper model is defined as:

    @Entity
    public class TaskHelper extends Model {
        Required
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @NaturalId
        public Task task;
    
        @Required
        @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @NaturalId
        public User user;
    }
    

    Let me know if you need any more details. thx

  • ransom-briggs (at uiowa)

    ransom-briggs (at uiowa) July 25th, 2014 @ 07:14 PM

    Again, sorry for the delayed response, work has been crazy, but I finally got around to checking out the RC for 1.3. I am running straight from the tag without any of my fixes and I get the following error, which I believe matches yours.

    /**
     * HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe
     * use of the session): org.hibernate.AssertionFailure: collection owner not associated with session:
     * models.route_builder.stops.Stop.conditions
     */
    

    I should have time enough on monday to take my patches put together a pull request for this.

  • Chris Webb

    Chris Webb July 25th, 2014 @ 08:05 PM

    Hi Ransom,

    Great news. Very interested to see your pull request!

  • ransom-briggs (at uiowa)

    ransom-briggs (at uiowa) July 28th, 2014 @ 04:22 PM

    Submitted a pull request: https://github.com/playframework/play1/pull/781

    Let me know if this fixes your problems.

  • Play Duck

    Play Duck July 31st, 2014 @ 03:26 AM

    (from [60111116095c3d8875fa46eb0cdcadce21b5d0d1]) [#1566] Update to hibernate 4.2.15 [#1566] Partial Fix TransientObjectException when orphanRemoval = true and removing and adding items [#1503] Partial fix Nested OneToMany relationships with orphanRemoval fails to commit [#1847] Partial fix Orphan removal not cascaded for @OneToOne relationships https://github.com/playframework/play1/commit/60111116095c3d8875fa4...

  • Chris Webb

    Chris Webb August 4th, 2014 @ 08:14 AM

    Hi Ransom,

    Your changes plus Alexandre's have resolved all of my issues.Thanks for all your help.

  • Play Duck

    Play Duck August 8th, 2014 @ 03:27 AM

    (from [172e4ef774ff629b42260f302b244bdbc1f18a2d]) [#1566] Update to hibernate 4.2.15 [#1566] Partial Fix TransientObjectException when orphanRemoval = true and removing and adding items [#1503] Partial fix Nested OneToMany relationships with orphanRemoval fails to commit [#1847] Partial fix Orphan removal not cascaded for @OneToOne relationships

    Conflicts:
    framework/src/play/db/jpa/JPABase.java https://github.com/playframework/play1/commit/172e4ef774ff629b42260...

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2>Play framework</h2>

Play makes it easier to build Web applications with Java. It is a clean alternative to bloated Enterprise Java stacks. It focuses on developer productivity and targets RESTful architectures. Learn more on the <a href="http://www.playframework.org">http://www.playframework.org</a> website.<br><br>

<h2>Source code is hosted on github</h2>Check out our repository at <a href="http://github.com/playframework/play">http://github.com/playframework/play</a><br><br>

<h2>Contributing, creating a patch</h2> Please read the <a href="http://play.lighthouseapp.com/projects/57987/contributor-guide">contributor guide</a><br><br>

<h2>Reporting Security Vulnerabilities</h2> Since all bug reports are public, please report any security vulnerability directly to <em>guillaume dot bort at gmail dot com</em>.<br><br>

<h2>Creating a bug report</h2> Bug reports are incredibly helpful, so take time to report bugs and request features in our ticket tracker. We’re always grateful for patches to Play’s code. Indeed, bug reports with attached patches will get fixed far quickly than those without any.<br><br>

Please include as much relevant information as possible including the exact framework version you're using and a code snippet that reproduces the problem.<br><br>

Don't have too much expectations. Unless the bug is really a serious "everything is broken" thing, you're creating a ticket to start a discussion. Having a patch (or a branch on Github we can pull from) is better, but then again we'll only pull high quality branches that make sense to be in the core of Play.

Attachments

Referenced by

Pages