I have a couple of domain objects which I am trying to save using the Cascade functionality. However, when I add a child to a parent and save the parent, the child object is not saved.
Update: The original version of the code here did not flush the session, which could have explained the behavior I saw. It didn’t, however, and I’ve updated the code in the quesiton to better reflect the actual situation.
This is what I do in my controller and repository:
// in controller
public ActionResult AddChildToParent(int id /* of parent */, ChildInputModel input)
{
var child = GetChildFromInputModel(input); // pseudo
var savedchild = _repo.AddChildToParent(c, id);
// savedchild.Id is still 0, and nothing has been saved to the database.
return View(savedchild);
}
// in repo
public IChild AddChildToParent(IChild c, int parentId)
{
var parent = GetParentById(parentId);
var child = new Child();
c.CopyValuesTo(child); // A utility function in our library
parent.AddChild(child);
// These two calls might be unnessesary, but I'm keeping them here to sho
// my current code situation
var session = GetNHibernateSession();
session.Save(parent);
return child;
// session flushes when method returns thanks to injected transactions
}
I don’t see the error in my application until I’m redirected to the edit page and the ID is 0, but I’ve verified in the database that no child record is added. I’m not changing anything else on the parent – just adding a child.
What am I doing wrong here?
These are my entities and maps (simplified):
public class Parent : IParent // Interface just defines everything public
{
public int Id { get; set; }
public string Name { get; set; }
private IList<Child> _children;
public IList<Child> Children
{
get
{ return _children ?? (_children = new List<Child>()); }
}
public void AddChild(Child c)
{
this.Children.Add(c);
c.Parent = this;
}
}
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(p => p.Id);
Map(p => p.Name);
HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}
}
public class Child : IChild // Interface just defines everything public
{
public int Id { get; set; }
public string Name { get; set; }
public Parent Parent { get; set; }
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Id(c => c.Id);
Map(c => c.Name);
References(c => c.Parent).Not.Nullable();
}
}
That’s normal: cascades are not stored immediately. The children get the ids after the next flush (which may take time, so don’t flush explicitly after each call to
AddChild) or after explicitly saving the child.