[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