This is fairly easy to resolve with the QueryOver API and a Future - sorry, I 
don't use the LINQ API.  With QueryOver, you can do something like this:

 

var postFuture = session.QueryOver<Blog>().Fetch(x => x.Posts).Future();

var commentFuture = session.QueryOver<Blog>().Fetch(x => x.Comments).Future();

 

var blogsWithPostsAndComments = postFuture.ToList();                            
  // Executes both Future queries above in one batch

 

We succesfully use this technique quite a lot with large graphs to avoid the 
issues you're describing.

 

HTH,

/Pete

 

From: [email protected] [mailto:[email protected]] On Behalf Of 
Jacenty
Sent: 12 June 2013 16:15
To: [email protected]
Subject: [nhusers] Cascading fetch

 

Hello

I have to read quite complex graph of entities for large processing. From one 
hand - I'd like to avoid lazy loading - because it leads to N+1 problem, from 
another - using fetches with ore than one collection in one query leads to 
cartesion product in generated sql, that is unefficient, and to duplicates in 
retrieved data (even in collections implementing relationships) which breaks a 
domain model consistency.
Considering the simple example Blog -> Post -> Comment, when trying to query 
all blogs with posts and comments fetched, we can try something like that:

var blogs = session.Query<Blog>().FetchMany(b => b.Posts).ThenFetchMany(p => 
p.Comments);


Since it produces following SQL:

select 
    blog0_.Id as Id0_0_, ...
from [Blog] blog0_ 
        left outer join [Post] posts1_ on blog0_.Id=posts1_.Blog_id 
        left outer join [Comment] comments2_ on posts1_.Id=comments2_.Post_id


If there is more than one comment for one post, the post would be duplicated in 
a Posts collection of its blog - my domain model becomes inconsistent.
I made a workaround by making two queries (it's similar, but not the same 
solution, as Ayende's advice here 
<http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate>
 ):

var blogs = session.Query<Blog>().FetchMany(b => b.Posts);
var posts = session.Query<Post>().FetchMany(p => p.Comments);


Unfortunately, NHibernate doesn't match fetches from the second query with 
posts fetched in the first query, comments are read again for each post when 
navigating through comments collection, and I still have the N+1 problem.
Probably, after executing the second query, there are two instances of each 
post held by one session, which is bug in my opinion.

I solved it by replacing comment collections of posts fetched by first query:

var blogs = this.session.Query<Blog>().FetchMany(b => b.Posts);
var posts = this.session.Query<Post>().FetchMany(p => 
p.Comments).ToDictionary(p => p.Id);

foreach (var blog in blogs)
{
    foreach (var post in blog.Posts)
    {
        post.Comments = posts[post.Id].Comments;
    }
}


But I think it's to weird code.
Does anybody know some more elegant solution?

Regards,
Jacek Hełka

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/nhusers?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/nhusers?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to