NHibernate assocations muitos-para-muitos, tornando ambas as extremidades como pai, usando uma entidade de relacionamento no Modelo de Domínio
Entidades: Team <-> TeamEmployee <-> Employee
Requisitos:
Uma equipe e um empregado podem existir sem sua contraparte.Na relação Team-TeamEmployee, a equipe é responsável (pai) [usando mais tarde um TeamRepository].Na relação Employee-TeamEmployee, o empregado é responsável (pai) [usando mais tarde um EmployeeRepository].Duplicados não são permitidos.A exclusão de uma equipe exclui todos os funcionários da equipe, se o funcionário não estiver em outra equipe.A exclusão de um funcionário exclui apenas uma equipe, se a equipe não contiver mais funcionários.Mapeamento:
public class TeamMap : ClassMap<Team>
{
public TeamMap()
{
// identity mapping
Id(p => p.Id)
.Column("TeamID")
.GeneratedBy.Identity();
// column mapping
Map(p => p.Name);
// associations
HasMany(p => p.TeamEmployees)
.KeyColumn("TeamID")
.Inverse()
.Cascade.SaveUpdate()
.AsSet()
.LazyLoad();
}
}
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);
// associations
HasMany(p => p.TeamEmployees)
.Inverse()
.Cascade.SaveUpdate()
.KeyColumn("EmployeeID")
.AsSet()
.LazyLoad();
HasMany(p => p.LoanedItems)
.Cascade.SaveUpdate()
.LazyLoad()
.KeyColumn("EmployeeID");
}
}
public class TeamEmployeeMap : ClassMap<TeamEmployee>
{
public TeamEmployeeMap()
{
Id(p => p.Id);
References(p => p.Employee)
.Column("EmployeeID")
.LazyLoad();
References(p => p.Team)
.Column("TeamID")
.LazyLoad();
}
}
Criando Funcionários e Equipes:
var employee1 = new Employee { EMail = "Mail", FirstName = "Firstname", LastName = "Lastname" };
var team1 = new Team { Name = "Team1" };
var team2 = new Team { Name = "Team2" };
employee1.AddTeam(team1);
employee1.AddTeam(team2);
var employee2 = new Employee { EMail = "Mail2", FirstName = "Firstname2", LastName = "Lastname2" };
var team3 = new Team { Name = "Team3" };
employee2.AddTeam(team3);
employee2.AddTeam(team1);
team1.AddEmployee(employee1);
team1.AddEmployee(employee2);
team2.AddEmployee(employee1);
team3.AddEmployee(employee2);
session.SaveOrUpdate(team1);
session.SaveOrUpdate(team2);
session.SaveOrUpdate(team3);
session.SaveOrUpdate(employee1);
session.SaveOrUpdate(employee2);
Depois disso eu confirmo as alterações usando transaction.Commit (). A primeira coisa estranha é que eu tenho que salvar equipes e funcionários em vez de apenas um deles (por quê ?!). Se eu apenas salvar todas as equipes ou (Xor) todos os funcionários, então eu recebo umTransientObjectException:
"objeto faz referência a uma instância transitória não salva - salve a instância transitória antes da limpeza. Tipo: Core.Domain.Model.Employee, Entity: Core.Domain.Model.Employee"
Quando eu salvo todos os times e funcionários criados, tudo é salvo, MAS a tabela de relações TeamEmployee temasassociações duplicadas.
ID EID TID
1 1 1
2 2 1
3 1 2
4 2 3
5 1 1
6 1 2
7 2 3
8 2 1
Então, ao invés de 4 relações existem 8 relações. 4 relações para o lado esquerdo e 4 relações para o lado direito. : [
O que eu estou errado?
Outras questões: Quando eu excluo uma equipe ou um funcionário, eu tenho que remover a equipe ou o funcionário da lista TeamEmployee no modelo de objeto ou NHibernate fazer o trabalho para mim (usando session.delete (..))?