Search code examples
nhibernatefluent-nhibernatemappingnhibernate-mappingfluent-nhibernate-mapping

Fluent NHibernate HASMANY mapping without references


I am a beginner at using Fluent NHibernate. I am developing a C# application that has to interact with an existing database.Let say I have 2 tables: Items and ItemsList.

Items:     ID INT     ItemName VARCHAR(100)
ItemsList: ID INT     ChildItemID INT

I've built 2 classes and their mapping:

public class Items
{
    public virtual int id {get; set;}
    public virtual string itemName {get; set;}

}

public class ItemsMap : ClassMap<Items>
{
    public ItemsMap()
    {
        Id(x => x.id).GeneratedBy.Increment();
        Map(x => x.itemsName);
    }
}


public class ItemsList()
{
    public virtual int id {get; set;}
    public virtual IList<Items> childItems {get; set;}

    public ItemsList()
    {
        childItems = new List<Items>();
    }
}

public class ItemsListMap : ClassMap<ItemsList>
{        
    public ItemsListMap()
    {
        Id(x => x.id).GeneratedBy.Increment();
        HasMany(x => x.childItems).KeyColumn("childID").Cascade.All();
    }
}

And finally, I insert an item in the itemsList and save it all:

try
{
    using( ISession session = NH.OpenSession())
    {
        using(ITransaction transaction = session.BeginTransaction())
        {
            Items i = New Items()
            i = session.get<Items>(1);

            ItemsList il = new ItemsList();
            il.childID.Add(i);
            session.SaveOrUpdate(il);
            transaction.Commit();
        }
    }        
}

So when I commit, I have a new entry in ItemsList table, but the childID is blank.

Question:

All the examples I see has a reference to ItemsListID in Items table. But I don't want to have this reference since I want the item to be unique in the items table. How can I acheve that?


Solution

  • The NHibernate native way for expressing the unique reference, is:

    5.1.12. one-to-one

    There are two varieties of one-to-one association:

    • primary key associations
    • unique foreign key associations

    Primary key associations don't need an extra table column; if two rows are related by the association then the two table rows share the same primary key value. So if you want two objects to be related by a primary key association, you must make sure that they are assigned the same identifier value!...

    Other words, Tables would look like this (Table Items generates the value of ItemID, table ItemsList takes that value and stores it in the ItemID ) :

    Items:     ItemID INT     ItemName VARCHAR(100)
    ItemsList: ItemID INT 
    

    The C# would be (I changed Items into Item and ItemList into ItemMoreDetails, because it is not a list anymore)

    public class Item
    {
        public virtual int ItemId { get; set; }
        ...
        public virtual ItemMoreDetails ItemMoreDetails {get; set; }
    
    public class ItemMoreDetails
    {
        public virtual int ItemId { get; set; }
        ...
        public virtual Item Item {get; set;}
    

    The mapping would be (in fluent):

    // Parent side
    public class ItemMap : ClassMap<Item>
    {
        public ItemMap()
        {
            Id(x => x.id).GeneratedBy.Increment();
            ...
            HasOne(x => x.ItemMoreDetails).Cascade.All();
    
    // child side
    public class ItemMoreDetailsMap: ClassMap<ItemMoreDetails>
    {
        public ItemMoreDetailsMap()
        {
            ...
            References(x => x.parent).Unique();
    

    See the doc:

    HasOne / one-to-one