1

エンティティ:チーム<->TeamEmployee<->従業員

要件:

  • チームと従業員は、対応するものがなくても存在できます。
  • Team-TeamEmployeeの関係では、チームが責任を負います(親) [後でTeamRepositoryを使用]。
  • Employee-TeamEmployeeの関係では、従業員が責任を負います(親) [後でEmployeeRepositoryを使用します]。
  • 複製は許可されていません。
  • 従業員が別のチームに属していない場合、チームを削除すると、チーム内のすべての従業員が削除されます。
  • チームに従業員が含まれていない場合、従業員を削除すると、チームのみが削除されます。

マッピング:

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

従業員とチームの作成:

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

この後、transaction.Commit()を使用して変更をコミットします。最初の奇妙なことは、チームと従業員を1つだけではなく、保存する必要があることです(なぜですか?!)。すべてのチームまたは(Xor)すべての従業員のみを保存すると、TransientObjectExceptionが発生します。

「オブジェクトは保存されていない一時インスタンスを参照しています-フラッシュする前に一時インスタンスを保存してください。タイプ:Core.Domain.Model.Employee、エンティティ:Core.Domain.Model.Employee」

作成したすべてのチームと従業員を保存すると、すべてが正常に保存されますが、リレーションテーブルTeamEmployeeには重複した関連付けがあります。

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

したがって、4つの関係の代わりに8つの関係があります。左側に4つの関係、右側に4つの関係。:[

何が間違っていますか?

その他の質問:チームまたは従業員を削除する場合、オブジェクトモデルのTeamEmployeeリストからチームまたは従業員を削除する必要がありますか、それともNHibernateが(session.delete(..)を使用して)私に代わって仕事をしますか?

4

4 に答える 4

2

あなたはビジネスロジックについて話している。ビジネス ロジックを実装することは NHibernate の目的ではありません。

あなたのコードが何をしているのか:

TeamEmployeeの 2つの異なるコレクションをマップTeamしましたEmployee。コードでは、アイテムを両方のコレクションに追加し、TeamEmployeeそれぞれの時間の新しいインスタンスを作成します。では、NHibernate がこれらの個別のインスタンスをすべて格納すべきではないと考えるのはなぜでしょうか?

それを修正するためにあなたができること:

エンティティを作成TeamEmployeeしました (値型とは対照的)。インスタンスを 1 回だけ作成するには、メモリ内でインスタンス化を 1 回だけ行い、両方のコレクションで再利用する必要があります。これは、ドメイン モデルでこのクラスが本当に必要な場合にのみ行ってください。(例: 関係に関する追加情報が含まれており、実際には独自のエンティティであるため。)

クラスが必要ない場合は、多対多の関係としてマッピングする方がはるかに簡単です ( Chris Conwayによって既に提案されています)。同じデータを含むと予想されるメモリには 2 つのコレクションがあるため、Inverse.

両端の親問題

両端に親はありません。チームも従業員もお互いの親ではなく、独立していることは明らかだと思います。おそらく、それらは両方とも中間の親であることを意味しますTeamEmployee。同じインスタンスの親 (したがって所有者) になることはできません。それらのいずれかが親であるか、別の独立したインスタンスであるため、管理がはるかに複雑になります (これが現在の実装方法です)。多対多の関係としてマッピングすると、NHibernate によって管理されます。

ビジネス ロジックで行うには:

  • 新しいチームと新しい従業員の保存
  • 関係の管理と同期の維持
  • 使用されなくなったチームと従業員を削除します。(いくつかの理由から、NHibernate には明示的に永続的なガベージ コレクションの実装はありません。)
于 2010-01-01T23:26:00.233 に答える
1

2 つの HasMany マップではなく、HasManyToMany が必要なようです。また、そのテーブルにマップが必要な他のプロパティがない限り、TeamEmployeeMap は必要ありません。もう 1 つのことは、Inverse() を設定する必要があるのは片側だけであり、チームを従業員に追加しているので、TeamMap を逆にする必要があると思います。逆を片側だけにすると、データベース内の重複するエントリが取り除かれます。

多分このようなもの:

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

これを使用すると、削除によりデータベースから TeamEmployee が削除されます。

于 2009-12-18T14:58:30.947 に答える
1

このチュートリアルを確認してください。具体的には、Productとの間のマッピングがどのようにStore設定されているかを確認してください。

于 2009-12-18T15:00:26.200 に答える
0

NHibernate は、両端で親との多対多の関連付けを許可しません。

于 2009-12-30T09:52:39.187 に答える