views:

469

answers:

2

Hi All

NHibernate noob here. Looking for advice on how to map the following common scenario:

[Store]
id pk
Name

[StockItem]
id pk
Name

[StockItemStore]
id pk
StockItemId fk
StoreId fk
ParLevel

I have created a domainmodel that allows various StockItems to be assigned to various Stores via the StockItem Entity using a AssignToStore(Store store) method.

I am now using nhibernate to create my db schema. How do I setup the mapping files for this basic scenario?

Any tips greatly appreciated.

Chev

+1  A: 

I would strongly recommend reading up on nHibernate. Here's a very good starting point:

The nHibernate FAQ

I would also recommend that you do the mappings by hand the first couple of times. After that, you should check out Fluent nHibernate. Fluent nHibernate can (among other things) automatically generate the mappings for you from your domain model and also help you to generate the database schema. It is a very flexible tool that is getting better and better. You'll find it here:

Fluent nHibernate

Good luck!

tmatuschek
+1  A: 

Hi,

Unfortunately this relationship isn't the easiest thing to model in nHibernate and there are some inherent problems you will encounter when trying to do queries on the data in the linking table, that will require some complicated workarounds, but once you get it set up it works quite well.

My approach to this is to set it up as two many-to-one mappings with the following relationship in the Store mapping and the inverse relationship in the StockItem mapping.

<bag name="StockItems" table="StockItemStore" lazy="true">
  <key column="StoreId" />
  <composite-element class="SuperStore.Components.StockItemStore, SuperStore.Components">
    <property name="ParLevel" type="Int32" />
    <many-to-one name="StockItem" column="StockItemId" class="SuperStore.Components.StockItem, SuperStore.Components" fetch="join" cascade="all" />
  </composite-element>
</bag>

the Store class will have the following collection:

public virtual IList< StockItemStore > StockItems {get;set;}

and StockItem will have the inverse again:

public virtual IList< StockItemStore > Stores {get;set;}

The StockItemStore object is able to contain either object (Store or StockItem) and any additional information that is in the linking table. (in this case just the ParLevel.

depending on which side you are looking at the StockItemStore object from either Store or StockItem will null. It could be broken out into two classes, but I find this approach easier to work with. It just requires you as the developer to know which side you are approaching it from, but its a good tradeoff for making the code simpler and more reusable in my opinion

public class StockItemStore
{
    private StockItem stockItem;
    private Store store;

    public virtual StockItem StockItem
    {
        get
        {
            if (stockItem == null)
            {
                stockItem = new StockItem();
            }

            return stockItem;
        }
        set
        {
            stockItem = value;
        }
    }

    public virtual Store store
    {
        get
        {
            if (store == null)
            {
                store = new Store();
            }

            return store;
        }
        set
        {
            store = value;
        }
    }

    public virtual int ParLevel { get; set; }

}

My approach doesn't use the single unique identifier in the StockItemStore as you defined in your question, but rather what amounts to a composite key in the linking table. But it has served me well in the past overall. I'm sure you could shoehorn that id in somehow if you really needed it.

This approach works great for querying using HQL. if you are trying to use ICriteria queries it tends to get a little wonky. There are some solutions out there with using database views to simulate another table to use for querying that have worked for me.

If you need to do ICriteria queries let me know and I can post some sample code.

  • Max
Max Schilling
I forgot to mention, I removed it for simplicity of the code example for the StockItemStore class, but you should *always* implement Equals and GetHashCode in your nHibernate objects
Max Schilling
I had done pretty much the same and have been using fluent to create the mappings. interesting thing is that when i use the automapping feature of fluent the entities seem to need an id property? looking into this at the moment - thanks for the tips!
Chev

related questions