views:

323

answers:

4

Hi,

I have currently moved my blogengine over from Linq2Sql to NHIbernate.

I'm stuck at the following performance problem: I got one table: 'Posts', that has Id, Title, PostContent, DateCreated collumns and so on.

The problem is that, when I'm creating the "Recent posts list", I don't want the whole PostContent.

In Linq2Sql you can set lazy loading on a single property, so it won't be part of the SQL query until you actually ask for the property.

I tried doing this with Fluent NHibernate, by doing this:

Map(x => x.PostContent).LazyLoad();

It didn't work out. Googling around, it seems that NHibernate doesn't support this, so my question is, how can I fix this?

Is it really not possible to lazy load my property without moving the content to a seperate table?

Thanks in advance!

A: 

Use HQL instead of LINQ.

Kim Johansson
If I do this:<code>var posts = _unitOfWork.CurrentSession.CreateQuery("Select p.Id, p.Title, p.CreatedDate from Post p").List<Post>();</code>I get the following error:The value "System.Object[]" is not of type "Core.Domain.Post" and cannot be used in this generic collection.
J. Hovgaard
A: 

This is not possible when PostContent is mapped to the same table, because the performance difference is not significant in 99% of the situations. When you are in the 1%, you can consider using handbuild sql instead of a orm for that case.

Lazy/Eager loading is not possible at all with linq to sql (out of the box) as far as I know.

What you can do create a different class with the data you want to select and just select that data into a new object.

Paco
Hmm okay. Sounds like a solution. Can you make a small example of how you would do it?
J. Hovgaard
Lazy/Eager loading *is* possible with LinqToSql. It's just less flexible than NHibernate.
Michael Maddox
First, I would start a profiler and find the slowest part of the code. Than I would optimize that part first. Than repeat until fast enough. When fast enough is under 1/1000th of a second, I would hit the part of the query, that I would write like session.Linq<Post>().Select(post => new RecentPost(post.Property1, post.Property2).Take(10).ToList();
Paco
As requested, a good (almost identical) example for what you want to do, at least regarding setting up the mappings, is here: http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/11/17/lazy-loading-blobs-and-the-like-in-nhibernate.aspx
fostandy
+1  A: 

Here is how you can achieve what you want (kind of lazy loading but not the same)

var posts = NHibernateSessionManager.Session.CreateQuery("Select p.Id as Id, p.Title as Title, p.DateCreated as DateCreated from Post p")
       .SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof(Post)))
       .List<Post>();

What the AliasToBean is intended for is, doing selects for specific columns (usually from more than one entities) and return a strongly typed collection instead of a System.Object[].

Now if you Bean (class) is your Post class then it will popultate to that class ONLY the requested columns and nothing else.

What you will NOT be having though is a collection of NHibernate managed objects. All Posts in the returned lists are detached non controlled objects.

For doing things like "getting all recent posts" without having to get the most "heavyweight" columns of your entity while not having to create other classes to convert the data to, the above solution is kind of perfect.

Check this out for more info: http://stackoverflow.com/questions/1797920/nhibernate-returning-a-strongly-typed-list-having-applied-an-aggregate-function/

tolism7
Thanks! This really moved me forward. Btw, sorry for the slow reply.I was wondering how I should handle caching with this approach? As I understand, I can't cache anything in the 2nd layer cache, if its detached, like you say.
J. Hovgaard
No problem... I believe these objests are still getting in tht 2nd level cache. As I am not sure about that maybe you can find out by trying it with a test (unit test or just by debugging a second request to the same code to see if the query hits the database again or not - of course cache should be enabled in the Post mapping file).
tolism7
I did this actually, and it seems that as soon I use ResultTransfomer, the collections get uncacheable :/
J. Hovgaard
+2  A: 

Update: this capability is now available in the NHibernate trunk.

See details on Ayende's blog, where the sample is exactly the scenario you describe here.

Jay