1

I'm new to NHibernate but have a better understanding of EF4.

I have a basic "Edit Item" page, and on submit I want to update my Item object with values from the form. FWIW, I'm using a FormView and leveraging the new WebForms Model Binding features where practical.

My "Item" object has a property:

public virtual Category Category { get; set; }

which corresponds to a FK relationship in the database (column "CategoryId" pointing to table "Category".)

So my form has a "Category" dropdown. This dropdown has been loaded with a list of all the Category objects.

On submit, all I want to do is assign the selected value in the Category dropdown to the Category property of my Item object. Pretty straight forward, right? :)

However I ran into difficulty:

  • I can easily get the dropdown.SelectedValue, but I can't assign this to my Item object. In EF4, my Item object would use a Foreign Key Association and would thererfore have both Category and CategoryId properties, which would automatically be kept in sync. When I tried something similar in NHibernate I got a Invalid Index for this SqlParameterCollection error due to the attempted multiple use of a single column.

  • I an easily get the dropdown.SelectedItem, but this is of type ListItem, which cannot be cast to Category.

  • I tried making use of the dropdown.DataSource property (maybe accessing the "SelectedIndex-th" item), but when stepping through the code, this DataSource value was null.

My best (awful) solution so far is as follows:

var dropdown = (DropDownList)MyFormView.FindControl("dropdown");
var id = dropdown.SelectedValue;
var category = new MyRepository().GetCategoryById(id);
item.Category = category;

So I'm making an extra repository call, and getting the entire Category object again, when all I really want to do is:

item.CategoryId = id;

How should I be doing this?

Community
  • 1
  • 1
Merenzo
  • 5,326
  • 4
  • 31
  • 46

2 Answers2

1

Use Session.Load when you know the id to avoid a trip to the database. Load will create a dynamic proxy and allow the item to be persisted with the correct CategoryId. Load is the best solution in stateless applications.

var dropdown = (DropDownList)MyFormView.FindControl("dropdown");
var id = dropdown.SelectedValue; // may need to cast to int
item.Category = session.Load<Category>(id);
Jamie Ide
  • 48,427
  • 16
  • 81
  • 117
  • Thanks Jamie #2: this approach is similar to what I've already got, though I now (partially :) understand the differences between "Get" and "Load". In my situation (with "Session-per-request") there are no "Category" values in the current session at the time of postback. So it is still making a database hit to retrieve the full Category object, when all I want to do is set the CategoryId (which I already have) on the "item" object. – Merenzo Nov 12 '12 at 00:56
  • Load should do that. However, I'm seeing in my own code that it sometimes still hits the database. There are two reasons I know if when this will occur: lazy loading is disabled or a property other than the id is accessed. – Jamie Ide Nov 12 '12 at 13:55
0

You do not need to get the category object, you can just create a new category object and dynamically set the id.

var dropdown = (DropDownList)MyFormView.FindControl("dropdown");
var id = dropdown.SelectedValue;
item.Category = new Category { CategoryId = id };
UnitStack
  • 1,175
  • 1
  • 11
  • 28
  • Thanks Jamie #1, though it didn't work for me. First error: "object references an unsaved transient instance". I then added "cascade=All" to the FK definition in my HBM. This gave a second error: "could not insert: [Category#MyID]".... NH is interpreting your "new Category {}" statement as a request to insert. – Merenzo Nov 12 '12 at 00:38