I came across a problem with a Schema Fluent Nhibernate was generating for me yesterday. I was getting the error message “Repeated column in mapping for collection”.
I had an object, let’s call it “Item” which referenced instances of the same type, let’s call them “AssociatedItems”.
Thinking of a simple real-life example, when you do an oil change on your car you should change the oil filter and the sump-plug washer too. So an oil filter Item would have associated items of oil and sump-plug washer. Sump-plug washer would have associated items of oil and oil filter etc.
So the object looked something like this :
public class Item
{
public virtual int Id {get; set;}
public virtual string Code {get; set;}
public virtual string Description {get; set;}
public virtual string IList<Item> AssociatedItems {get; set;}
}
Looks pretty straighforward. Now to the Mapping :
Public ItemMap()
{
Id(x => x.Id);
Map(x => x.Code);
Map(x => x.Description);
HasManyToMany(x => x.AssociatedItems);
}
OK, really simple.
Generating the schema, a table to handle the many-to-many relationships between Items and AssociatedItems is created. It’s called something wierd like AssociatedItemsToAssociatedItems though and it only has one field / column called “Item_Id”. I’m also getting an error message “repeated column in mapping for collection – Item_Id” – What’s going on? The database generation seems to be getting confused because of the self reference / relationship and is trying to create a table with field name “Item_Id” for the parent object and “Item_Id” for the child object.
Getting around the problem was quite straightforward though and only involved a change to the mapping class.
If you provide NHibernate with specific PK / FK names for the relationships it will generate a table with two fields of the specificed names, a composite key for the relationships. Great!
HasManyToMany(x => x.AssociatedItems)
.ParentKeyColumn("Item_Id")
.ChildKeyColumn("AssociatedItem_Id")
It still gives you a table with a crappy name though – bollocks! What you need to do now though is tell NHibernate what it should call the table holding the relationship, explicitly define the name of the relationship table :
.Table("AssociatedItemToItem");
So, the new, working map definition is :
Public ItemMap()
{
Id(x => x.Id);
Map(x => x.Code);
Map(x => x.Description);
HasManyToMany(x => x.AssociatedItems)
.ParentKeyColumn("Item_Id")
.ChildKeyColumn("AssociatedItem_Id")
.Table("AssociatedItemToItem");
}