How to delete a child from a bidirectional many-to-many association?
How can I delete a child from a bidirectional many-to-many association?
Deleting the child does not work because I get an exception (FK Violation).
Just removing the child from the parent and call saveorupdate on the parent does not do anything.
Entities:
public class Employee : Entity
{
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual string EMail { get; set; }
public virtual IList<LoanedItem> LoanedItems { get; set; }
public virtual ISet<Team> Teams { get; set; }
public Employee()
{
if (LoanedItems == null)
{
LoanedItems = new List<LoanedItem>();
}
if (Teams == null)
{
Teams = new HashedSet<Team>();
}
}
public virtual void AddTeam(Team team)
{
Teams.Add(team);
team.Employees.Add(this);
}
public virtual void RemoveTeamFromEmployee(Team team)
{
Teams.Remove(team);
}
}
public class Team : Entity
{
public virtual string Name { get; set; }
public virtual ISet<Employee> Employee开发者_开发问答s { get; set; }
public Team()
{
if (Employees == null)
{
Employees = new HashedSet<Employee>();
}
}
public virtual void RemoveEmployeeFromTeam (Employee employee)
{
var result = Employees.Remove(employee);
}
public virtual void AddEmployee(Employee employee)
{
Employees.Add(employee);
employee.Teams.Add(this);
}
}
Mappings:
public class TeamMap : ClassMap<Team>
{
public TeamMap()
{
// identity mapping
Id(p => p.Id)
.Column("TeamId")
.GeneratedBy.Identity();
// column mapping
Map(p => p.Name);
// Employee is responible for the relationship
HasManyToMany(p => p.Employees)
.Table("TeamEmployee")
.AsSet()
.LazyLoad()
.Inverse()
.Cascade.SaveUpdate()
.ParentKeyColumn("TeamId")
.ChildKeyColumn("EmployeeId")
.NotFound.Ignore();
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
// identifier mapping
Id(p => p.Id)
.Column("EmployeeId")
.GeneratedBy.Identity();
// column mapping
Map(p => p.EMail);
Map(p => p.LastName);
Map(p => p.FirstName);
// Employee is responible for the relationship
HasManyToMany(p => p.Teams)
.Table("TeamEmployee")
.AsSet()
.LazyLoad()
.ParentKeyColumn("EmployeeId")
.ChildKeyColumn("TeamId")
.Cascade.SaveUpdate()
.NotFound.Ignore();
HasMany(p => p.LoanedItems)
.Cascade.SaveUpdate()
.KeyColumn("EmployeeId");
}
}
EDIT
Code to delete a team:
//Test Case 2
//Delete Team 2
Team team = session.Get<Team>(2);
List<Employee> employees = team.Employees.ToList();
foreach (var employee in employees)
{
team.RemoveEmployeeFromTeam(employee);
}
session.Delete(team);
If it is a many-to-many, then one direction is the "master" direction. The other direction will have inverse="false"
defined. You have to remove from the collection the right way round - to be sure (and to truly represent what your deletion is achieving), delete both. Then flush the session to have this persisted.
Example:
if A
has a collection of objects of type B
, and vice versa, then to remove the association between two particular instances, you have to delete the instance of A
from the instance of B
's collection and vice versa. Then when the session is flushed, NHibernate knows to delete the relevant row from the linking table.
Edit now you've posted code
Try changing the two methods like so:
public virtual void RemoveTeamFromEmployee(Team team)
{
Teams.Remove(team);
team.Employees.Remove(this);
}
public virtual void RemoveEmployeeFromTeam (Employee employee)
{
Employees.Remove(employee);
employee.Teams.Remove(this);
}
To tidy up your code to delete a team, which is not responsible for the relationship, you do have to iterate over the linked employees. However, if you have to delete teams more frequently than employees, then you may find it more convenient to reverse this, and then you can just use:
team.Employees.Clear();
session.Delete(team);
精彩评论