Search code examples
c#.netnhibernatenhibernate-mapping

Mapping recursive association using nhibernate


I have poco class

public class Category : Entity<int>
{
    public virtual Category Parent;
    public virtual Iesi.Collections.Generic.ISet<Article> Articles {get; set;}
    public virtual Iesi.Collections.Generic.ISet<Category> ChildCategories {get; set;}
}

I'm not sure is this correct mapping for ChildCategories property

public class CategoryMap : ClassMapping<Category>
{
    public CategoryMap()
    {
       ...
       Set(x => x.ChildCategories,
          c => { c.Cascade(Cascade.DeleteOrphans); },
          r => { r.OneToMany(); }              
       );
    }
}

Any child category can have only one parent. Once more is this correct mapping? If you need more information please ask.

Update: Exception inner message is following

{"Could not determine type for: xxxx, 
for columns: NHibernate.Mapping.Column(Parent)"}

Update 2:

public class CategoryMap : ClassMapping<Category>
    {
        public CategoryMap()
        {
            Id(x => x.Id, m => m.Generator(Generators.GuidComb));

            Property(x => x.Name, m =>
            {
                m.Length(255);
                m.NotNullable(true);
            });

            Property(x => x.Parent, m =>
            {
                //m.NotNullable(true);
            });

            Set(x => x.ChildCategories,
              c => 
              { 
                c.BatchSize(25);
                c.Inverse(true);
                c.Cascade(Cascade.DeleteOrphans); 
                c.Key(k =>
                {
                    k.Column("ParentId");
                });
              },
              r => { r.OneToMany(); }              
           );


            Set(x => x.Articles,
              c => { c.Cascade(Cascade.DeleteOrphans); },
              r => { r.OneToMany(); }
            );            
        }
    }

Update 3

Property(x => x.Parent, m =>
            {
                m.Column("ParentId");
                m.NotNullable(true);
            });

Error

{"Could not determine type for: xxxx, 
for columns: NHibernate.Mapping.Column(ParentId)"}

Solution

  • Not so sure what the real issues is, but my standard xml mapping for parent-child collection would look like this:

    <set name="ChildCategories" lazy="true"  batch-size="25" inverse="true">
      <key column="ParentId" />
      <one-to-many class="Category"/>
    </set>
    

    While lazy is (as far as I remember) default, I prefer explicit statements

    I would say, that really essential is the information where to search for a Parnet column. This I would mapp for sure explicitly. And also the inverse and batch-size. So, following

    This could be the mapping of the set

     ...
     Set(x => x.ChildCategories,
          c => 
          { 
            c.BatchSize(25);
            c.Inverse(true);
            c.Cascade(Cascade.DeleteOrphans); 
            c.Key(k =>
            {
                k.Column("ParentId");
            };
          },
          r => { r.OneToMany(); }              
       );
    

    Few more information about why to use batch-sizing: How to Eager Load Associations without duplication in NHibernate?

    Because we used (in my snippet) the Inverse ... the Parent must be mapped as well (and assigned)

    UPDATE: The essential part of this mapping is the Parent mapping!

    But Parent is not a value type property. It is a reference. That's why we have to map it like this:

    ManyToOne(x => x.Parent, m =>
    {
    

    See: Mapping-by-Code - ManyToOne

    we cannot use

    // NOT correct mapping
    Property(x => x.Parent