w0ns88
w0ns88

Reputation: 345

nHibernate HasMany within the same table causes StackOverflowException

I have an entity called Category which contains many subcategories of the same Entity (Category):

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

        public Category()
        { }

        public Category(Category category)
        {
            SubCategories = category.SubCategories.Where(c => !c.Deleted).Select(c => new Category(c)).ToList();
        }
    }

Here is my mapping for the Category:

public class CategoryMap : NHibernateMap<Category>
    {
        public CategoryMap()
        {
            Map(x => x.Name);
            HasMany(x => x.SubCategories).KeyColumn("ParentId").Cascade.AllDeleteOrphan().AsBag();
            References(x => x.ParentCategory, "ParentId");
        }
    }

The database seeds fine and I can easily add a new Category at the top level. But as soon as I try to add a category under another, I get the following exception:

Process is terminating due to StackOverflowException.

Here is the code for when I try to create a Category:

public Category CreateCategory(CreateCategoryModel model)
        {
            var category = new Category
            {
                Name = model.Name,
            };
            if (model.ParentCategory == null) return category; // Up to here it works fine. - I save the category elsewhere.

            var parent = Get(model.ParentCategory.Id);
            category.ParentCategory = parent;
            parent.SubCategories.Add(category);
            _categoryRepository.SaveOrUpdate(parent);

            return category; // If I hit these lines of code I get the StackOverflow exception
        }

Some pointers of what I am doing wrong or how to fix the issue would be much appreciated.

Thanks in advance :)

Upvotes: 0

Views: 163

Answers (2)

w0ns88
w0ns88

Reputation: 345

I found the issue where the StackOverflowException was happening. There was recursion in subcategories > parent > subcategories > parent, creating an endless loop.

I did not look int the approach of using Inverse as stated by @collenbrecht but I went for a different approach, changing my data structure a little:

Instead of saving a whole ParentCategory object on the Category, I save its Id only. And I fetch the whole object when needed. This removes the endless loop and solves my issue.

My Category class looks like this now:

 public class Category : Entity
    {
        public virtual string Name { get; set; }
                public virtual IList<Category> SubCategories { get; set; } = new List<Category>();
        public virtual long? ParentId { get; set; }

        public Category()
        { }

        public Category(Category category)
        {
            SubCategories = new List<Category>();
        }
    }

And the mapping like so:

 public class CategoryMap : NHibernateMap<Category>
    {
        public CategoryMap()
        {
            Map(x => x.Name);
            Map(x => x.ParentId);
            HasMany(x => x.SubCategories).Cascade.AllDeleteOrphan();
        }
    }

In my service I can then do the following:

public Category CreateCategory(CreateCategoryModel model)
        {
            var category = new Category
            {
                Name = model.Name,
            };
            if (model.ParentCategory == null)
            {
                category.ParentId = null;
                return category;
            }

            var parent = Get(model.ParentCategory.Id);
            parent.SubCategories.Add(category);
            _categoryRepository.SaveOrUpdate(parent);
            category.ParentId = model.ParentCategory.Id;

            return category;
        }

Upvotes: 0

collenbrecht
collenbrecht

Reputation: 44

maybe inverse() can help?

HasMany(x => x.SubCategories).KeyColumn("ParentId").Inverse().Cascade.AllDeleteOrphan().AsBag();

Upvotes: 1

Related Questions