views:

952

answers:

2

I'm using Castle ActiveRecord, but this question applies to NHibernate, too, since a solution that works with NHibernate should work for ActiveRecord. Anyway, what I have is an underlying table structure like this:

TableA -hasMany-> TableB

I have corresponding objects EntityA and EntityB. EntityA has an IList of EntityB objects. This part works fine. Now, I want EntityB to have some kind of reference back to EntityA. I know I can use the BelongsTo attribute on EntityB to give it an actual reference back to the full EntityA type, like:

[BelongsTo("tableAid")] public EntityA Parent { get; set; }

But what I'd really like to do is:

[BelongsTo("tableAid")] public int ParentId { get; set; }

So, EntityB would store only the ID of the parent object, not a reference to the actual object. This is a trivial example, but I have good reasons for wanting to go with this approach. In the application I'm working on, we have pages that display specific EntityB-like objects, and we'd like for those pages to include links (as in hyperlinks) to the corresponding parent pages. We can do that by using the first approach above, but that requires that the entire EntityA object be loaded when all I really need is the ID. It's not a huge deal, but it just seems wasteful. I know I can use lazy-loading, but again, that seems more like a hack to me...

I have tried flagging the foreign key with the [Property] attribute like so:

[Property] public int ParentId { get; set; }

The problem with this approach is that EntityB.ParentId remains null when you do a EntityA.SaveAndFlush() on a new object tree. The correct value is being written to the database, and I can force the value back into EntityB.ParentId by doing an EntityA.Refresh(), but again, that seems like a bit of a hack.

A: 

Just this:

[Property] public int ParentId { get; set; }

...assuming "ParentId" is the actual column name.

A couple of other comments.

First, you should consider lazy loading many-to-one properties anyway. If you eagerly load them, you must be aware of possible cascades of eager loads, which can make a serious performance hit. To do this you must mark all public members of the lazily loaded class as virtual.

Second, be aware that any time you have a one-to-many association with no corresponding relation from the child back to the parent, you must make the FK nullable in the database. That's because when NH creates new child items, it will insert it with the parent id null and then in a second step update it.

Tim Scott
Thanks for the suggestion. I had actually already tried this approach, I just forgot to list it in the question. It does mostly work, but not perfectly. :(
DanMan
+2  A: 

Lazy loading is exactly what you want - and it's not a hack either, it's a well tested and baked in part of NHIbernate and an important tool when performance tuning any substantial NHibernate app.

If you were to mark your "parent" EntityA as lazy loaded, referring to EntityB.Parent.Id would not load EntityA at all (as behind the scenes NHIbernate has already loaded EntityA's id when loading EntityB) - thus letting you setup your links without incurring a performance penalty.

Jonathan Moffatt