NHibernate many-to-many assocations beide Enden als Eltern machen, indem eine Beziehung Entität in der Domain-Modell

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

Frage

Instanzen: Team <-> TeamEmployee <-> Mitarbeiter

Anforderungen:

  • A-Team und ein Mitarbeiter ohne sein Pendant existieren.
  • Im Team-TeamEmployee Beziehung das Team verantwortlich ist (Eltern) [mit später TeamRepository].
  • In der Mitarbeiter TeamEmployee Beziehung der Mitarbeiter verantwortlich ist (übergeordneten) [mit später eine EmployeeRepository].
  • Dubletten sind nicht erlaubt.
  • Löschen ein Team löscht alle Mitarbeiter im Team, wenn der Arbeitnehmer nicht in einem anderen Team ist.
  • Löschen ein Mitarbeiter löscht nur ein Team, wenn das Team nicht nicht mehr Mitarbeiter enthalten.

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

Erstellen von Mitarbeitern und Teams:

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

Danach lege ich die Änderungen durch transaction.commit () verwenden. Die erste Merkwürdige ist, dass ich speichern Teams und Mitarbeiter statt nur einem von ihnen (warum ?!). Wenn ich nur speichern alle Teams oder (Xor) alle Mitarbeiter dann erhalte ich eine TransientObjectException :

  

"Objektreferenzen eine nicht gespeicherte   transiente Instanz - Speichern Sie die   transiente Instanz vor dem Spülen.   Typ: Core.Domain.Model.Employee,   Entity: Core.Domain.Model.Employee "

Wenn ich speichern alle bestehenden Teams und Mitarbeiter alles spart in Ordnung, aber die Beziehung Tabelle TeamEmployee hat doppelte 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

So anstelle von 4 Beziehungen gibt es 8 Beziehungen. 4 Beziehungen für die linke Seite und 4 Beziehungen für die rechte Seite. [

Was mache ich falsch?

Weitere Fragen: Wenn ich ein Team oder Mitarbeiter löschen, muß ich das Team oder die Mitarbeiter aus der TeamEmployee Liste im Objektmodell zu entfernen oder nicht NHibernate macht den Job für mich (mit session.delete (..) )?

War es hilfreich?

Lösung

Sie sprechen über Business-Logik. Es ist nicht der Zweck der NHibernate der Geschäftslogik zu implementieren.

Was ist Ihr Code tut:

kartiert Sie zwei verschiedene Sammlungen von TeamEmployees, einen in Team, einen in Employee. In Ihrem Code, fügen Sie Elemente zu beiden Sammlungen, neue Instanzen von TeamEmployee Erstellung jedes Mal. Also, warum Sie erwarten, dass NHibernate nicht alle diese verschiedenen Instanzen gespeichert werden sollte?

Was Sie tun können, um es zu beheben:

Sie hat diese Entität (im Gegensatz zu einem Werttyp) TeamEmployee. Um nur einmal eine Instanz zu erstellen, würden Sie haben es instanziiert nur einmal im Speicher und wieder verwendet es in beiden Sammlungen. Tun Sie dies nur, wenn Sie wirklich diese Klasse in Ihrem Domain-Modell benötigen. (Z. B. weil sie zusätzliche Informationen über die Beziehungen enthalten und ist eigentlich eine gesonderte Einheit bildet.)

Wenn Sie nicht die Klasse benötigen, ist es viel einfacher, es zu kartieren als many-to-many-Beziehung (wie bereits vorgeschlagen, durch Chris Conway ). Da es zwei Kollektionen im Speicher sind, die zu erwarten sind, die gleichen Daten enthalten, Sie NHibernate sagen, einen von ihnen zu ignorieren, wenn die Speicherung, Verwendung Inverse.

Die Eltern an beiden Enden Problem

Es gibt keine Eltern an beiden Enden . Ich denke, es ist klar, dass weder das Team noch die Mitarbeiter ein Elternteil des anderen ist, sie unabhängig sind. Sie meinen wohl, dass sie beide Elternteile des Zwischen TeamEmployee sind. Sie können nicht seine Eltern (und damit Eigentümer) von der gleichen Instanz. Entweder einer von ihnen ist die Mutter, oder es ist eine andere unabhängige Instanz, die es viel komplizierter macht die Verwaltung (das ist, wie Sie es jetzt umgesetzt). Wenn Sie es als eine many-to-many-Beziehung abbilden, wird es von NHibernate verwaltet werden.

Um durch Ihre Geschäftslogik durchgeführt werden:

  • neue Teams und neue Mitarbeiter zu speichern
  • die Beziehungen Verwaltung und halten sie in sync
  • Löschen Teams und Mitarbeiter, wenn sie nicht mehr verwendet. (Es gibt ausdrücklich keine persistent Garbage Collection Umsetzung in NHibernate, aus mehreren Gründen.)

Andere Tipps

Sieht aus wie Sie benötigen einen HasManyToMany statt zwei HasMany Karten. Auch gibt es keine Notwendigkeit für die TeamEmployeeMap, wenn Sie eine andere Eigenschaft in dieser Tabelle haben die Bedürfnisse abgebildet. Eine andere Sache, nur eine Seite braucht die Inverse () Set zu haben, und da Sie Teams an Mitarbeiter sind das Hinzufügen ich glaube, Sie brauchen die TeamMap die invers zu machen. die inversen auf einer Seite nur die Beseitigung der doppelten Einträge in der Datenbank erhalten.

Vielleicht so etwas wie folgt aus:

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

Mit diesem, das Löschen wird den TeamEmployee aus der Datenbank für Sie löscht.

Schauen Sie sich dieses Tutorial , und zwar, wie die Zuordnung zwischen Product und Store eingerichtet ist.

NHibernate nicht zulässt, dass viele-zu-viele-Verein mit den Eltern an beiden Enden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top