wusher
wusher

Reputation: 12441

Nhibernate delete parent in many-to-one relationship causing foreign key violation

I have a Employer object that can have multiple People:

//entities 
public class Person {
    public virtual Guid Id {get;set;}
    public virtual string Name {get;set;}
    public virtual Employer CurrentEmployer {get;set;}
}

public class Employer {
    public virtual Guid Id {get;set;}
    public virtual string Name {get;set}
    public virtual IList<Person> Employees {get;set;}
}

//person to employer mappings 
References(x => x.CurrentEmployer)
    .Cascade.All()
    .Column("CurrentEmployerId")
    .ForeignKey("FK_Person_CurrentEmployer");

//employer to person mappings
HasMany(x=> x.Employees)
    .Inverse() 
    .Cascade.All();

When I try to delete an employer that is linked to a person, I get a "Foreign Key violation" error.

//example
_session.Delete(oldEmployer);

How do I get nHibernate to null the CurrentEmployerId column before the employer is deleted?

Upvotes: 2

Views: 1095

Answers (4)

stu
stu

Reputation: 8805

Oracle has the cascading delete feature (based on foreign key constraints) built in. Sybase does not. Depending on if your database supports before and after triggers you can create the functionality with before triggers. Sybase 12 doesn't have this, it only has after triggers so it's impossible on sybase. Sybase 15 has before triggers but I haven't tried it yet, but it should work, basically you write the before trigger manually to do the cascading delete.

If this before trigger functionality doesn't exist in your database, this is not possible. You would have to programmatically delete the child table rows first before deleting the parents.

That's just how it is.

Upvotes: 0

msi
msi

Reputation: 3212

Try to do this one

//employer to person mappings
HasMany(x=> x.Employees)
    .Inverse() 
    .Cascade.AllDeleteOrphan();

I didn't check it, but I hope it could help you.

Upvotes: 0

Jon Erickson
Jon Erickson

Reputation: 114846

try clearing all CurrentEmployer's first then deleting the Employee

public class Employer 
{
    public virtual Guid Id {get;set;}
    public virtual string Name {get;set}
    public virtual IList<Person> Employees {get;set;}

    public void UnemployAll()
    {
        foreach(var employee in Employees)
        {
            employee.CurrentEmployer = null;
        }
        Employees = new List<Person>(); // clear it
    }
}

then try the following (I think the employees (person) should all get updated), I don't know if this will work off the top of my head, but it may get you started in the right direction.

oldEmployer.UnemployAll();
_session.Delete(oldEmplorer);

Upvotes: 1

Chris Shaffer
Chris Shaffer

Reputation: 32575

Do you have code scattered all around that deletes employers? I think normally you would have only one place in the code really that deletes employers, so there wouldn't really be a need to have nhibernate do this work for you; Just have a statement there that updates all referencing employees.

If you actually do have these deletes scattered all about, then you could create an Interceptor or Event Listener that watched for deletes to the table and have the interceptor/Listener update referencing employees.

Upvotes: 0

Related Questions