Ayende @ Rahien

Unnatural acts on source code

Efficently loading deep object graphs

Here is an interesting approach to get deep object graphs effectively.  This will ensure that you will get all the relevant collections without having to lazy load them and without a huge cartesian product. Especially useful if you want to load a collection of items with the associated deep object graph.

public Policy GetPolicyEagerly(int policyId)
{
	IList list = ActiveRecordUnitOfWorkFactory.CurrentSession.CreateMultiQuery()
		.Add(@"from Policy policy left join fetch policy.PolicyLeadAssociations
where policy.Id = :policyId") .Add(@"from Policy policy left join fetch policy.PolicyEmployeeAssociations
where policy.Id = :policyId") .Add(@"from Policy policy left join fetch policy.PolicyManagerAssociations
where policy.Id = :policyId
") .Add(@"from Policy policy left join fetch policy.PolicyDepartmentAssociations
where policy.Id = :policyId
") .Add(@"from Policy policy left join fetch policy.PolicyCustomerAssociations
where policy.Id = :policyId
") .SetEntity("policy", Policy) .List(); IList firstResultList = (IList) list[0]; if(firstResultList.Count==0) return null; return = (Policy) firstResultList [0]; }

The domain above is a fake one, by the way, don't try to make any sense of it.

Comments

Frans Bouma
06/20/2007 09:01 PM by
Frans Bouma

You mean... there are o/r mappers out there which fetch graphs using cartesian products? :X

Ugh...

Ayende Rahien
06/20/2007 09:07 PM by
Ayende Rahien

I mean, that is one option that you have, yes.

Florent Dugue
06/21/2007 08:53 AM by
Florent Dugue

Sorry for my ignorance, but what's the difference with adding "SetFetchMode" ?

IList list = Session.CreateCriteria(typeof (Policy ))

            .SetFetchMode("PolicyLeadAssociations", FetchMode.Join)

            .SetFetchMode("PolicyEmployeeAssociations", FetchMode.Join)

            .SetFetchMode("PolicyManagerAssociations", FetchMode.Join)

            .SetFetchMode("PolicyDepartmentAssociations", FetchMode.Join)

            .SetFetchMode("PolicyCustomerAssociations", FetchMode.Join)

            .List();
Ayende Rahien
06/21/2007 08:55 AM by
Ayende Rahien

This will return a single result set.

The problem with that is that if you try to load all of that in a single result set, you will have a big Cartesian product.

The approach above uses separate queries, but only a single round trip

Sven
06/21/2007 08:56 AM by
Sven

Florent, I'm guessing what you wrote would cause the huge cartesian product Ayende mentioned.

Sven
06/21/2007 08:57 AM by
Sven

Damn, he's just too quick, isn't he ? :-)

Florent Dugue
06/21/2007 09:08 AM by
Florent Dugue

Ok, if I understand well, you mean it's faster to do 5 requests with only one join between two tables in each request instead of one big request between the 6 tables ?

BTW, I forgot the .Add(new EqExpression("Id", policyId)) between CreateCritera and the first SetFetchMode for removing the Cartesian product.

@Sven : yeah, damn fast ! ;)

Ayende Rahien
06/21/2007 09:57 AM by
Ayende Rahien

@ Florent,

Yes, that would be faster, but the key part here is that it is 5 request, but a SINGLE round trip

Jim Geurts
06/30/2007 04:10 PM by
Jim Geurts

I may be mistaken, but shouldn't the line:

.SetEntity("policy", Policy)

be

.SetInt32("policyId", policyId)

Allen
07/05/2007 08:40 PM by
Allen

I'm wondering what is the Hibernate equivalent syntax for achieving this since there's no CreateMultiQuery() function?

Ayende Rahien
07/05/2007 08:59 PM by
Ayende Rahien

Allen,

That is something that I added to NHibernate, Hibernate has no equivalent that I know of

Comments have been closed on this topic.