1

实体:团队 <-> TeamEmployee <-> 员工

要求:

  • 团队和员工可以在没有对应的情况下存在。
  • 在 Team-TeamEmployee 关系中,团队负责(父级) [稍后使用 TeamRepository]。
  • 在 Employee-TeamEmployee 关系中,Employee 负责(父) [稍后使用 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() 提交更改。第一个奇怪的事情是我必须保存团队和员工,而不是只保存其中一个(为什么?!)。如果我只保存所有团队或(异或)所有员工,那么我会得到一个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您映射了两个不同的s集合,一个 in Team,一个 in EmployeeTeamEmployee在您的代码中,您将项目添加到两个集合中,每次都创建新实例。那么为什么你认为 NHibernate 不应该存储所有这些不同的实例呢?

你可以做些什么来解决它:

您创建了TeamEmployee一个实体(与值类型相反)。要只创建一次实例,您必须只在内存中实例化一次并在两个集合中重用它。仅当您在域模型中确实需要此类时才这样做。(例如,因为它包含有关关系的附加信息并且实际上是它自己的实体。)

如果您不需要该类,则将其映射为多对多关系要容易得多(正如Chris Conway已经提出的那样)。因为内存中有两个集合应该包含相同的数据,所以你告诉 NHibernate 在存储时忽略其中一个,使用Inverse.

两端的父母问题

两端都没有父级。我认为很明显,团队和员工都不是对方的父母,他们是独立的。您可能的意思是他们都是中间人的父母TeamEmployee。他们不能是同一实例的父(因此也是所有者)。它们中的一个是父级,或者是另一个独立的实例,这使得管理它变得更加复杂(这就是你现在实现它的方式)。如果将其映射为多对多关系,它将由 NHibernate 管理。

由您的业务逻辑完成:

  • 存储新团队和新员工
  • 管理关系并使它们保持同步
  • 不再使用团队和员工时删除它们。(由于几个原因,NHibernate中明确没有持久的垃圾回收实现。)
于 2010-01-01T23:26:00.233 回答
1

看起来您需要一个 HasManyToMany 而不是两个 HasMany 地图。此外,除非您在该表中有其他需要映射的属性,否则不需要 TeamEmployeeMap。另一件事,只有一侧需要设置 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 回答