NHibernate molti-a-molti association facendo entrambe le estremità come un padre utilizzando un'entità relazione nel Modello di Dominio

StackOverflow https://stackoverflow.com/questions/1928591

Domanda

Entità: Squadra <-> TeamEmployee <-> dipendenti

Requisiti:

  • Una squadra e un impiegato può esistere senza la sua controparte.
  • Nel rapporto squadra-TeamEmployee il team è responsabile (genitore) [utilizzando poi un TeamRepository].
  • Nel rapporto dipendente-TeamEmployee è responsabile del Dipendente (genitore) [utilizzando poi un EmployeeRepository].
  • I duplicati non sono ammessi.
  • L'eliminazione di una squadra elimina tutti i dipendenti nella squadra, qualora il lavoratore non è in un altro team.
  • L'eliminazione di un Dipendente elimina solo una squadra, se la squadra non contiene nessun più dipendenti.

Mapping:

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();
    }
}

La creazione di Dipendenti e Squadre:

    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);

Dopo questo mi impegno le modifiche utilizzando transaction.Commit (). La prima cosa strana è che devo salvare Squadre e dipendenti invece solo uno di loro (perché ?!). Se salvo solo tutte le squadre o (XOR) a tutti i dipendenti, allora ho un TransientObjectException :

  

"riferimenti agli oggetti un salvati   transitoria esempio - per salvare la   esempio transitoria prima del lavaggio.   Tipo: Core.Domain.Model.Employee,   Entità: Core.Domain.Model.Employee "

Quando ho salvare tutti creati Squadre e dipendenti tutto salva bene, ma il tavolo TeamEmployee relazione ha duplicato assoications .

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

Così, invece di 4 rapporti ci sono 8 rapporti. 4 rapporti per il lato sinistro e 4 rapporti per il lato destro. : [

Che cosa mi sbaglio?

Altre domande: Quando si elimina una squadra o un dipendente, devo rimuovere il team o il dipendente dall'elenco TeamEmployee nel modello a oggetti o fa NHibernate rendere il lavoro per me (utilizzando Session.delete (..) )?

È stato utile?

Soluzione

Si sta parlando di logica di business. Non è lo scopo di NHibernate per implementare la logica di business.

Che cosa il vostro codice sta facendo:

È mappato due diverse raccolte di TeamEmployees, uno in Team, uno in Employee. Nel codice, si aggiungono elementi entrambe le collezioni, la creazione di nuove istanze di TeamEmployee ogni volta. Allora, perché si aspetta che NHibernate non dovrebbe memorizzare tutti questi casi distinti?

Che cosa si potrebbe fare per risolvere il problema:

È TeamEmployee fatto un'entità (a differenza di un tipo di valore). Per creare un'istanza solo una volta, si dovrà istanziare solo una volta nella memoria e riutilizzarla in entrambe le collezioni. Solo fare questo quando si ha realmente bisogno di questa classe nel vostro modello di dominio. (Ad es. Perché contiene ulteriori informazioni sui rapporti e in realtà è un'entità a sé stante.)

Se non avete bisogno della classe, è molto più facile per mappare come una relazione molti-a-molti (come già proposto da Chris Conway ). Perché ci sono due collezioni in memoria che dovrebbero contenere gli stessi dati, si dice NHibernate di ignorare uno di loro durante la memorizzazione, utilizzando Inverse.

Il genitore su entrambe le estremità problema

Non c'è genitore su entrambe le estremità . Penso che sia chiaro che né la squadra né il dipendente è un genitore dell'altro, sono indipendenti. Probabilmente significa che sono entrambi i genitori della TeamEmployee intermedio. Non possono essere genitore (e quindi proprietario) della stessa istanza. Uno di loro è il genitore, o è un altro esempio indipendente, che rende la gestione è molto più complicato (questo è come si implementato ora). Se si mappa come una relazione molti-a-molti, sarà gestito da NHibernate.

Per essere fatto dalla logica di business:

  • la memorizzazione di nuovi team e nuovi dipendenti
  • gestione dei rapporti e il loro mantenimento in sincronia
  • Squadre eliminazione e dipendenti quando non sono più utilizzati. (Non v'è alcun esplicito persistente raccolta dei rifiuti implementazione in NHibernate, per diversi motivi.)

Altri suggerimenti

Sembra che avete bisogno di un HasManyToMany invece di due mappe hasMany. Inoltre, non v'è alcuna necessità per il TeamEmployeeMap a meno che non si dispone di qualche altra proprietà a quel tavolo che ha bisogno di mappato. Un'altra cosa, solo un lato ha bisogno di avere il set Inverso () e dal momento che si sta aggiungendo squadre ai dipendenti Penso che è necessario per rendere il TeamMap l'inverso. Avendo l'inverso su un solo lato permetterà di eliminare le voci duplicate nel database.

Forse qualcosa di simile:

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id)
           .Column("TeamID")
           .GeneratedBy.Identity();

        // column mapping
        Map(p => p.Name);

        // associations
        HasManyToMany(x => x.TeamEmployees)
            .Table("TeamEmployees")
            .ParentKeyColumn("TeamID")
            .ChildKeyColumn("EmployeeID")
            .LazyLoad()
            .Inverse()
            .AsSet();
    }
}

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
        HasManyToMany(x => x.TeamEmployees)
            .Table("TeamEmployees")
            .ParentKeyColumn("EmployeeID")
            .ChildKeyColumn("TeamID")
            .Cascade.SaveUpdate()
            .LazyLoad()
            .AsSet();

        HasMany(p => p.LoanedItems)
            .Cascade.SaveUpdate()
            .LazyLoad()
            .KeyColumn("EmployeeID");
    }
}

Con questo, la cancellazione eliminerà i TeamEmployee dal database per voi.

questo tutorial , e in particolare come il mapping tra Product e Store è impostato.

NHibernate non consente molti-a-molti con i genitori ad entrambe le estremità.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top