I have a parent table with an optional 1:1 relationship with a child table (the parent can exists without the child, but not vice-versa). The auto-generated primary key of the parent table is used as the primary/foreign key of the child.
Thanks to a couple good references (this question and this site), I was able to get a working 1:1 relationship mapped out. I can create a parent with or without a child, update one or both, and deleting the parent cascades to delete the child, as expected.
However, I want to somehow 'simulate' the Cascade.AllDeleteOrphan()
option of a HasMany
mapping within my HasOne
mapping structure, so that if the child end of the relationship is removed, the corresponding row in the child table will be deleted when the parent object is saved. As is, if I try to remove the child manually, I understandably get a 'deleted object would be re-saved by cascade'
error message.
Has anyone found a good way to do this while still only using HasOne
mappings? Would what I am trying to do still even be a 1:1 relationship, or should I just be using one-to-many and rely on my database constraints and business logic to prevent multiple children?
Simplified code:
// Parent class
public partial class Parent
{
public int pkParentID { get; set; }
public Child child { get; set; }
public Parent() { }
}
// Child class
public partial class Child
{
public int pkParentID {get; set; }
public Parent parent { get; set; }
public Child() { }
public Child(Parent parent) { this.parent = parent; }
}
// Parent mapping
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Table(@"Parent");
LazyLoad();
Id(x => x.pkParentID)
.Column("pkProjectID")
.Not.Nullable()
.GeneratedBy.Identity();
HasOne<Child>(x => x.Child)
.PropertyRef(r => r.Parent)
.Cascade.All();
}
}
// Child map
public class ChildMap :ClassMap<Child>
{
public ChildMap()
{
Table(@"Child");
LazyLoad();
Id(x => x.pkParentID, "pkParentID")
.GeneratedBy.Foreign("Parent");
HasOne<Parent>(x => x.Parent)
.Constrained()
.ForeignKey()
.Cascade.None();
}
}
// Ideally, the code snippet below would remove the row from the Child table
Parent parent = service.GetById(uniqueID);
if (parent.Child != null)
parent.Child = null;
service.SaveOrUpdate(parent);
// Just in case, here's my repository code
public virtual void SaveOrUpdate(T entity)
{
ISession _session = NHibernateSessionProvider.GetSession();
if (!_session.Transaction.IsActive)
{
using (ITransaction transaction = _session.BeginTransaction())
{
try
{
_session.SaveOrUpdate(entity);
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
}
}
EDIT:: I have also tried the following code snippet, which is what gives me the 'deleted object would be re-saved by cascade' error message.
...
Parent parent = parentService.GetById(uniqueID);
if (parent.Child != null)
{
childService.Remove(parent.Child); // this gives the above error
parent.Child = null;
}