views:

114

answers:

3

Entities

We have an entity called Product which is loaded using NHibernate.

Product has a category which NHibernate happily populates for me.

Database

In the database, Product has a foreign key for category.

Scenario

User edits this Product (via a web interface) and chooses a different category (say instead of "Fish" we select "Veg").

This is probably a dropdown list, with each category shown. When they choose a different category we get an int key.

Problem

Obviously we now want to save the changes to Product but in effect the only change is to save a new int (say 2, instead of 1).

So we retrieve the existing Product, and now comes the problem.

We don't have a "CategoryID" field on Product, we only have a Category property.

But we don't really want to retrieve the category (by id) just to assign it to the Product.

So I guess what I want to know is should we...

a) Add a CategoryID property to Product

b) Create a new category, assign it the relevant id and attach that to Product (but surely that will cause errors, or overwrite the existing category)

c) Retrieve (lookup) the category from the system (by id) and attach that to the Product

d) Do something else entirely!

A: 

Use NH's EnumStringType<T> to map your Category as an enum to the respective database value (which can be a string or a number). You'll find quite a few usage examples, if you google for it.

HTH!

Thomas Weller
+3  A: 

It looks like you might be able to using the Session.Load(id) functionality.

Session.Load is a special method that returns a proxy with the ID until you request another property at which point it loads. It throws an error if there is no item matching the ID. Try something like:

product.Category = Session.Load<Category>(2); //2 being the new category ID

Session.SaveOrUpdate(product);

I just did a little testing and it did not seem to pull back the entire Category.

Michael Gattuso
now I'm not sure which way to do it...I use Load when I'm updating an existing entity, but are you also supposed to use Load for each reference? hmmm
dotjoe
A good rule in NHibernate is to make the setter of the Identity column private or protected. This would not permit you to assign the Id as you did in your answer. Check out SharpArchitecture for a good implementation along with how to tinker with Id in testing.As stated Session.Load does nothing with the database unless a property is requested so we are essentially doing the same thing as your answer just with a smarter object that can resolve itself if needed.
Michael Gattuso
excellent point
dotjoe
+1  A: 

Updated: Session.Load is the correct answer

product.Category = session.Load<Category>(2);

session.Save(product);
dotjoe
Yep that seems to work.The only slight complication I had was that for a nullable datetime field I needed to ensure that my mappings and model reflected the fact that it was nullable (otherwise NHibernate threw an error about invalid datetime values)
jonhilt
but that nullable date was on the product (not the category) right?
dotjoe
+1 I got your back again. :)
Dusty