Search code examples
c#nhibernatefluent-nhibernatestack-overflow

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 :)


Solution

  • 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;
            }