在修改与NHibernate的多对多关系时防止删除/插入

时间:2011-04-20 10:15:32

标签: c# .net nhibernate fluent-nhibernate composite-key

在我的域模型中,User与许多Places关联 - 关系通过UserPlace类和映射(使用FluentNHibernate)建模如下(User有一个名为 Neighborhood 的UserPlace集合:

public class UserMap : ClassMap<User>
{
    HasMany(x => x.Neighbourhood)
      .Component(c =>
        {
          c.Map(x => x.IsDefault).Not.Nullable();
          c.Map(x => x.Selected).Not.Nullable().Default("0");
          c.References(x => x.Place).Fetch.Join();
        }
      ).Not.LazyLoad().Cascade.SaveUpdate();
}

每当我修改属于用户的任何UserPlace实体,然后将用户持久保存到数据库时,该用户的所有UserPlace行都将被删除,然后重新插入

我认为这是因为NHibernate不知道如何从另一行中唯一地识别这些行中的一行。换句话说,我的映射中的组件没有这样的键。

可以通过组合存储这两个实体之间关系的表中的User_id和Place_id列来形成主键。如何使用Fluent设置此密钥?这会解决我看到的删除和重新插入行为吗?

编辑:我在NHUsers上询问过此事,Fabio Maulo建议使用IdBag。据我所知,Fluent NHibernate不支持这一点 - 组件不允许使用标识符。我还能如何映射这种多对多关系并阻止delete-all-reinsert-all问题?

编辑2:以下是NH根据我的映射生成的表

CREATE TABLE [dbo].[User](
[Id] [uniqueidentifier] NOT NULL,
--- a bunch of unimportant fields
CONSTRAINT [PK__User] PRIMARY KEY CLUSTERED ([Id] ASC))

CREATE TABLE [dbo].[Neighbourhood](
[User_id] [uniqueidentifier] NOT NULL,
[IsDefault] [bit] NOT NULL,
[Place_id] [int] NOT NULL,
[Selected] [bit] NOT NULL)

CREATE TABLE [dbo].[Place](
[Id] [int] IDENTITY(1000,1) NOT NULL,
--- a bunch of unimportant fields
CONSTRAINT [PK_Place] PRIMARY KEY CLUSTERED ([Id] ASC))

User.Id和Neighbourhood.User_Id之间以及Neighbourhood.Place_id和Place.Id之间存在FK关系

2 个答案:

答案 0 :(得分:1)

您可以像这样映射此关系,以避免遇到您遇到的情况:

public class UserMap : ClassMap<User>
{
    HasMany(x => x.Neighbourhood)
      .KeyColumn("User_id")
      .Not.LazyLoad().Cascade.SaveUpdate();
}

public class NeighborHoodMap : ClassMap<NeighborHood>
{
    Table("Neighbourhood");
        CompositeId()
            .KeyReference(x => x.User, "User_id")
            .KeyReference(x => x.Place, "Place_id");

    Map(x => x.IsDefault).Not.Nullable();
    Map(x => x.Selected).Not.Nullable().Default("0");
}

邻居类看起来像这样:

public class NeighborHood
{
    public virtual User User { get; set; }
    public virtual Place Place { get; set; }
    public virtual bool IsDefault { get; set; }
    public virtual bool Selected { get; set; }

    public override bool Equals(object obj)
    {
       //check here to make sure these objects are equal (user_id and place_id are the same)    
    }

    public override int GetHashCode()
    {
        return User.Id.GetHashCode() ^ Place.Id.GetHashCode();
    }
}

答案 1 :(得分:0)

我不熟悉Fluent,但作为解决方法,您可以在UserPlace表上定义主键,以便NH可以跟踪更改。

只是一个想法。