4
votes

I am new to NHibernate and I am having trouble mapping the following relationships within this class.

public class Category : IAuditable
{
    public virtual int Id { get; set; }
    public virtual string Name{ get; set; }
    public virtual Category ParentCategory { get; set; }
    public virtual IList<Category> SubCategories { get; set; }

     public Category()
    {
        this.Name = string.Empty;
        this.SubCategories = new List<Category>();
    }

}

Class Maps (although, these are practically guesses)

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);

        References(x => x.ParentCategory)
            .Nullable()
            .Not.LazyLoad();

        HasMany(x => x.SubCategories)
            .Cascade.All();

    }
}

Each Category may have a parent category, some Categories have many subCategories, etc, etc I can get the Category to Save correctly (correct subcategories and parent category fk exist in the database) but when loading, it returns itself as the parent category.

I am using Fluent for the class mapping, but if someone could point me in the right direction for just plain NHibernate that would work as well.

2
Are you automapping or have you defined classmaps? If you are using classmaps, can you post your mappings?snicker
OK, I updated with my class maps, although I am not sure if they are anything close.Charlie Brown

2 Answers

2
votes

Ok so on the HasMany(x=>x.SubCategories) you need to add Inverse() to the call chain and also give it the column name which I'm assuming is "ParentCategoryId" given the mapping of the parent category, of course this depends on your conventions too.

If you were to post your table stucture I can give you a complete solution.

4
votes

By convention, Fluent NHibernate will look at "Category_Id" as foreign key column. It won't figure out your "ParentCategoryId" column. Unless you rename your self-referencing column to "Category_Id", you have to clarify the column name for both parent and child relationships.

For category without parent (absolute-parent category), whose reference column is null, it's reasonable to return itself as parent or null depending on how NHibernate handles it since you choose eager loading.

public class CategoryMap : ClassMap<Category> 
{ 
    public CategoryMap() 
    { 
        Id(x => x.Id); 
        Map(x => x.Name); 

        References(x => x.ParentCategory)
            .Column("ParentCategoryId")    // Many-To-One : parent
            .Nullable() 
            .Not.LazyLoad(); 

        HasMany(x => x.SubCategories) 
           .Cascade.All().Inverse().KeyColumn("ParentCategoryId");   //One-To-Many : chidren

    } 
}