views:

48

answers:

1

I have very simple situation and really don't have a clue why this isn't working.

This is my schema:

**[item]**
id (PK)
symbol

**[item_version]**
id (PK)
item_id (FK->ITEM)
symbol

These are my mappings:

item.hbm.xml

<class name="Core.Model.Entities.Item, Core.Model" table="item" lazy="false">
    <id name="Id" column="id" type="long">
        <generator class="native" />
    </id>
    <property name="Symbol" column="symbol"/>

    <bag name="ItemVersions" lazy="false" table="item_version" inverse="true" cascade="save-update">
        <key column="item_id" />
        <one-to-many class="Core.Model.Entities.ItemVersion, Core.Model"/>
    </bag>
</class>

*item_version.hbm.xml*

<class name="Core.Model.Entities.ItemVersion, Core.Model" table="item_version" lazy="false">
    <id name="Id" column="id" type="long">
        <generator class="native" />
    </id>

    <many-to-one name="Item" class="Core.Model.Entities.Item, Core.Model" column="item_id" cascade="save-update"/>
    <property name="Symbol" column="symbol"/>
    </class>

These are the classes:

Item.cs

public class Item : Entity<IItemDao>
{
   private long id;
   virtual public long Id
   {
       get { return this.id; }
       set { this.id = value; }
   }
   private string symbol;
   virtual public string Symbol
   {
       get { return this.symbol; }
       set { this.symbol = value; }
   }
   private IList<ItemVersion> item_versions = new List<ItemVersion>();
   virtual public IList<ItemVersion> ItemVersions
   {
       get { return this.item_versions; }
       set { this.item_versions = value; }
   }
}

ItemVersion.cs

public class ItemVersion : Entity<IItemVersionDao>
{
    private long id;
    virtual public long Id
    {
         get { return this.id; }
         set { this.id = value; }
    }
    private Item item = null;
    virtual public Item Item
    {
         get { return this.item; }
         set { this.item = value; }
    }
    private long item_id = 0;
    virtual public long ItemId
    {
         get { return this.item_id; }
         set { this.item_id = value; }
    }
    private string symbol;
    virtual public string Symbol
    {
         get { return this.symbol; }
         set { this.symbol = value; }
    }
}

And this code...

Item item = new Item();
item.Name = "test";

ItemVersion v = new ItemVersion();
v.Symbol = "test version";
item.ItemVersions.Add(v);

Item.Dao.Save(tmp);

... does not work. It inserts an item and throws an exception while inserting item_version row, that item_version.item_id cannot be null. So item_id property isn't automatically set by NHibernate in ItemVersion object. Why cascade="save-update" and inverse="true" does not work in this case?

When I set manually, by adding this code:

v.Item = item;

and than call save, everything works fine, but this is not what I except from NHibernate - calling

item.ItemVersions.Add(v);

should be sufficient.

Am I doing something wrong or this is simply imposible? Thanks in advance for the answers :)

+1  A: 

You have to set v.Item because ItemVersions is inverse. That means the "other side" (the many-to-one) is in charge of maintaining the relationship.

This is standard practice; to make it easier to use just add a method to Item:

public void AddItemVersion(ItemVersion itemVersion)
{
    ItemVersions.Add(itemVersion);
    itemVersion.Item = this;
}
Diego Mijelshon
I removed inverse="true" from "bag" and still have the same exception... Is there a way to make one-to-many take care of the relationship?
Adam
Don't do that, it was correct before. See added helper method.
Diego Mijelshon
Ok, so now I know that helper methods are the only way. Thanks :)
Adam