[ajug-members] Order of cascaded deletes with hibernate

Les A. Hazlewood les at hazlewood.com
Thu Apr 28 12:41:42 EDT 2005


Yes, you might want to open a Jira issue.  It sounds like it might be a
worthwhile feature, if it doesn't intrude too much on the write-behind
algorithms.  Assign the issue to Gavin or Steve Ebersole (I can't
remember if the public site allows assigning to a specific Hibernate
team member or not).

To answer your eager fetching question in a hierarchy: 

In short - its no problem.

In detail -

Hibernate can eagerly fetch and initialize an infinite number of levels
_deep_ in a query, 1 collection _per level_.  Just be aware, that the
deeper you go, the bigger the performance hit due to all the join
conditions.  I don't recommend eagerly joining more than 3 or 4 levels
deep to maintain performance.

Lets take a look at an object graph.  The root of the object graph is a
plain instance, and we'll assume all children are collections ( I hope
the ascii art shows up ):

       A        
     / | \
    /  |  \
   B   C   D
 / | \     | \
E  F  G    H  I


So in the above graph, an instance A would have a Collection of B's, a
Collection of C's and a Collection of D's.

Each instance in the B collection has a Collection of E's, a Collection
of F's and a Collection of G's.

Likewise, each instance in the D collection has a Collection of H's and
I's.

Hibernate can eagerly fetch at most 1 collection _per level_ in the
hierarchy.

So what this means is that if you wanted to query for A with all B, E,
and C and D collections initialized, you'll be able to eagerly query for
A with B and E collections initialized, but you'll need to explicitly
initialize the C and D collections.

Meaning in one query, you can pull A--*B--*E  OR A--*B--*F OR A--*B--*G.

So an example code block query showing eagerly fetching the A--B--E
subgraph would be as follows:

public getAPartiallyInitialized( UUID id ) {

    Session session = ... //get hibernate session

    String queryString = 
        "from A a 
            left join fetch a.BList as b 
            left join fetch b.EList as e 
         where 
            a.id = :aId";

    A a = (A)session.list( queryString, id ).get( 0 ); 

    //A to B to E were retrieved and init'd
    //but we have to manually initialize 
    //B's _peers_ C and D:
    Hibernate.initialize( a.getCs() );
    Hibernate.initialize( a.getDs() );

    return a;
}

Similarly, if you wanted to pull D's H or I collections (or both), you'd
have to iterate over the D collection, and explicitly call
Hibernate.initialize( d.getHs() ) and/or Hibernate.initialize( d.getIs()
); 

In summary, you can go as deep as you want as long as you're only
pulling 1 collection per graph level, just be aware of the performance
implications.

Cheers,

Les

On Thu, 28 Apr 2005 11:08:04 -0400, "Roy Wells" <roy.g.wells at gmail.com>
said:
> Its not really buisness logic.  I simply want to delete all children
> of object A.  From the business side of things I don't care what order
> they are deleted in, except for the fact that it causes a constraint
> violation if you do it in the wrong order.
> 
> In principal all the data needed to figure out the proper order is in
> the Mapping document.  You simply have to look for any many-to-ones
> flagged not null and if both sides of that are flagged for delete
> during a cascade then make sure you delete the many side first.  Maybe
> this should be a jira issue.  Then again those extra checks might be
> hard on performance for an edge case.  Though its a little frustrating
> to have to break from Hibernates typical paradigm of simply deleteing
> the object and letting it cascade in this one case.
> 
> In any case thank you for the response.  Its nice to see someone out
> there is willing to answer hibernate questions.
> 
> While I'm at it, can I trouble you with one more?
> 
> Is it possible to initialize a 3 level or deeper hierarchy of objects
> with out doing an n+1 select.
> 
> Here is the example.
> 
> Class "A" has a one-to-many relation with class "B" which has a
> one-to-many relation with class "C".  A--*B--*C.
> 
> If I wanted to load A with its B collection initialized that is as
> simple as "from A a left join fetch a.bList".  However I want to load
> A with the B collection initialized and all of the B's C collections
> initialized.  Is that possible?
> 
> Thanks again for the help
> 
> Roy Wells.
> 
> 
> On 4/27/05, Les A. Hazlewood <les at hazlewood.com> wrote:
> > 
> > As a former Hibernate consultant (worked w/ Gavin, Steve, et. al), I'll
> > answer ;)
> > 
> > Hibernate does not support allowing you to control the order of cascade
> > execution.
> > 
> > Hibernate uses transactional write-behind algorithms for determining
> > which objects it needs to insert/update/delete and when.  This basically
> > means that it optimizes the order in which SQL statements are executed
> > automagically at the end of a transaction based on a number of things,
> > including dirty data, collection modification, etc.
> > 
> > Because Hibernate uses these optimization algos, it determines how
> > cascades will be executed, not the programmer.  This is the primary
> > reason why Hibernate is almost always faster than a comparable
> > appliation that uses hand-written JDBC calls.  It can do all sorts of
> > things like use the JDBC batch api, only execute sql upon transaction
> > commit, etc., all transparently to the programmer while increasing
> > performance.
> > 
> > However, because you need certain elements to be deleted before others,
> > this might be a red flag that what you require is more closely related
> > to business logic (your app requirements) and not raw persistence logic
> > (Hibernate's realm).  If this is the case, explicit manual deletion is
> > usually preferred since it will be obviously documented in your source
> > code, thereby clearly reflecting your application requirements.
> > 
> > Best regards,
> > 
> > Les
> > 
> > On Wed, 27 Apr 2005 12:30:17 -0400, "Roy Wells" <roy.g.wells at gmail.com>
> > said:
> > > To any hibernate gurus out there.
> > >
> > > I'm having an issue with cascaded deletes in hibernate.  I would ask
> > > this on the hibernate forum but that place gives answers at a snails
> > > pace.  In fact someone else allready asked it there and got ignored.
> > >
> > > Here is the setup: Class "A" is a parent to both "B" and "C", and has
> > > one-to-many collections of each.  Class "C" has a unidirectional
> > > many-to-one association with "B".  The one-to-many collections from
> > > "A" to both "B" and "C" are cascade delete.
> > >
> > > The problem arrises when hibernate triggers cascade deletes from "A"
> > > to "B" and "C" it needs to delete "C" first but it doesn't.
> > >
> > > Is there a way to control the order in which deletes are cascaded in
> > > hibernate.  Otherwise I guess i'll just turn off the cascade deletes
> > > and handle it with manual calls.
> > >
> > > I also thought I might solve this with a Hibernate Interceptor, but
> > > i've read that calling back into the session and triggering additional
> > > operations from a hibernate interceptor is not supported.
> > >
> > > Here is what the hibernate mapping essentially looks like.
> > >
> > > <hibernate-mapping >
> > >
> > >   <class name="A">
> > >     <id name="id"><generator class="native" /></id>
> > >     <bag name="bList inverse="true" lazy="true" cascade="all">
> > >       <key column="a_id"/>
> > >       <one-to-many class="B"/>
> > >     </bag>
> > >     <bag name="cList inverse="true" lazy="true" cascade="all">
> > >       <key column="a_id"/>
> > >       <one-to-many class="C"/>
> > >     </bag>
> > >   </class>
> > >
> > >   <class name="B">
> > >     <id name="id"><generator class="native" /></id>
> > >     <many-to-one name="a" column="a_id" not-null="true"/>
> > >   </class>
> > >
> > >   <class name="C">
> > >     <id name="id"><generator class="native" /></id>
> > >     <many-to-one name="a" column="a_id" not-null="true"/>
> > >     <many-to-one name="b" column="b_id" not-null="true"/>
> > >   </class>
> > >
> > > </hibernate-mapping>
> > >
> > > _______________________________________________
> > > ajug-members mailing list
> > > ajug-members at ajug.org
> > > http://www.ajug.org/mailman/listinfo/ajug-members
> >
> 
> _______________________________________________
> ajug-members mailing list
> ajug-members at ajug.org
> http://www.ajug.org/mailman/listinfo/ajug-members



More information about the ajug-members mailing list