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