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.
