2

I try to create a tree in single table using Fluent Nhibernate. Table must look like this: enter image description here

Model class:

public class Category
{
    public virtual int CategoryId { get; set; }
    public virtual string CategoryName { get; set; }
    public virtual Category ParentCategory { get; set; }
    public virtual IList<Category> ChildCategory { get; } = new List<Category>();
}

Mapping class:

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Id(x => x.CategoryId).GeneratedBy.Increment();
        Map(x => x.CategoryName).Not.Nullable();

        References(x => x.ParentCategory).Column("ParentCategoryId").Access.CamelCaseField();

        HasMany(x => x.ChildCategory)
            .Cascade.AllDeleteOrphan()
            .AsSet()
            .KeyColumn("CategoryId")
            .Access.CamelCaseField();
    }
}

ORM return following exception:

NHibernate.PropertyNotFoundException: Could not find property nor field 'childCategory' in class 'MyProj.Models.Category'

I'm only studying NH. What I'm doing wrong?

Frédéric
  • 9,364
  • 3
  • 62
  • 112
user6408649
  • 1,227
  • 3
  • 16
  • 40

2 Answers2

2

You cannot use auto-properties with a field access strategies. You need an explicit backing field for this to work, and its naming must match the naming strategy you have chosen.

So in your case, change your class to:

public class Category
{
    public virtual int CategoryId { get; set; }
    public virtual string CategoryName { get; set; }
    public virtual Category ParentCategory { get; set; }

    private ISet<Category> childCategory = new HashSet<Category>();
    public virtual ISet<Category> ChildCategory { get { return childCategory; } }
}

Since you are mapping that as a set, I have additionally changed your IList for an ISet.

If you want another name for the backing field, choose another naming strategy. See here a list of them for hbm mapping. (Or get it in NHibernate reference documentation.) Fluent should have the same strategies.

You may instead of using a backing field remove the .Access.CamelCaseField() from your mappings and add a setter to your ChildCategory property.

Frédéric
  • 9,364
  • 3
  • 62
  • 112
  • Thank you for answer. I fix `Category` class and get another exception `NHibernate.PropertyNotFoundException: Could not find property nor field 'parentCategory' in class 'MyProj.Models.Category'` – user6408649 May 28 '17 at 19:04
  • 1
    @Seva, remove `.Access.CamelCaseField()` from `ParentCategory` mapping. No need to use that when the property has a setter. – Frédéric May 28 '17 at 20:53
0

I changed mapping class on the following:

public class Category
    {
        private ISet<Category> childCategories;
        private Category parentCategory;

        public Category()
        {
            childCategories = new HashSet<Category>();
        }

        public virtual int CategoryId { get; protected set; }

        public virtual string CategoryName { get; set; }

        public virtual ReadOnlyCollection<Category> ChildCategories
        {
            get
            {
                return new ReadOnlyCollection<Category>(new List<Category>(childCategories));
            }
        }

        public virtual Category ParentCategory
        {
            get
            {
                return parentCategory;
            }
        }
}

And it is generate table with out exceptions.

user6408649
  • 1,227
  • 3
  • 16
  • 40