【问题标题】:NHibernate configuration for uni-directional one-to-many relation单向一对多关系的 NHibernate 配置
【发布时间】:2018-01-13 03:00:02
【问题描述】:

我正在尝试建立如下关系。每个Master项都有一个或多个Detail项:

public class Detail {
    public virtual Guid DetailId { get; set; }
    public virtual string Name { get; set; }
}
public class Master {
    public virtual Guid MasterId { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Detail> Details { get; set; }
}

和映射:

public class MasterMap : ClassMap<Master> 
{
    public MasterMap() 
    {
        Id(x => x.MasterId);
        Map(x => x.Name);
        HasMany(x => x.Details).Not.KeyNullable.Cascade.All();
    }
}
public class DetailMap : ClassMap<Detail> 
{
    public DetailMap() 
    {
        Id(x => x.Id);
        Map(x => x.Name);
    }
}

Master数据库表是:

masterId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL

详情是:

DetailId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL
MasterId   uniqueidentifier NULL
foreign key (masterId) references [Master]

我并不真正关心从 Detail 到 Master 的链接——换句话说,Detail 对象本身对我的域层不感兴趣。它们将始终通过它们的 Master 对象进行访问。

使用这样的代码:

Master mast = new Master 
{
    MasterId = new Guid(),
    Name = "test",
    Details = new List<Detail> 
    {
        new Detail { .DetailId = new Guid(), .Name = "Test1" },
        new Detail { .DetailId = new Guid(), .Name = "Test1" }
    }
};

using (transaction == Session.BeginTransaction) 
{
    Session.Save(mast);
    transaction.Commit();
}

这很好用,除了this post 中概述的一个疯狂限制:NHibernate 执行 INSERT 并将 Detail.MasterId 首先设置为 NULL,然后执行 UPDATE 将其设置为真正的 MasterId。

真的,我不想要 NULL MasterIds 的 Detail 条目,所以如果我将 MasterId 字段设置为 NOT NULL,INSERT 到 Detail 将失败,因为正如我所说 NHibernate 试图放入 MasterId = NULL。

我想我的问题归结为:

如何使上述代码示例与我现有的域模型一起使用(例如,不添加 Detail.Master 属性),并且数据库中的 Detail.MasterId 字段设置为 NOT NULL?

有没有办法让 Nhibernate 将正确的 MasterId 放在初始 INSERT 中,而不是之后运行 UPDATE?这个设计决定是否有理由? -- 我很难理解为什么会这样。

【问题讨论】:

    标签: nhibernate fluent-nhibernate one-to-many


    【解决方案1】:

    NH3 及更高版本允许在单向一对多映射的情况下更正保存实体,而不会烦人 save null-save-update 循环,如果您在 上同时设置 not-null="true"inverse="false"

    FluentNHibernate 代码 sn-p :

    public class MasterMap : ClassMap<Master> 
    {
        public MasterMap() 
        {
            Id(x => x.MasterId);
            Map(x => x.Name);
            HasMany(x => x.Details)
                .Not.Inverse()     //these options are very
                .Not.KeyNullable() //important and work only if set together 
                .Not.KeyUpdate()   //to prevent double update
                .Cascade.All();
        }
    }
    

    【讨论】:

    • 您确定它不会发出重复更新吗?我按照概述设置了我的映射,它在插入时正确设置了外键(而不是插入空值),但随后它会进行额外的数据库更新,将外键重置为插入时使用的相同值。看起来 VikciaR 正在经历,而其他几个人(基于赞成票)正在经历同样的事情。
    • 查询按预期工作,但 nhibernate 仍然在数据库上创建一个允许可为空值的列?这正常吗?
    【解决方案2】:

    你不能。要引用来自my answer 的链接关于您链接到的另一个问题:

    非常重要的说明:如果 &lt;one-to-many&gt; 关联的 &lt;key&gt; 列被声明为 NOT NULL,NHibernate 在创建或更新关联时可能会导致约束冲突。为防止此问题,您必须使用与标记为inverse="true" 的多值端(集合或包)的双向关联。请参阅本章后面对双向关联的讨论。

    编辑: 正如 Hazzik 正确指出的那样,这在 NHibernate 3 及更高版本中发生了变化。遗憾的是,文档还没有更新,所以这里是 Hazzik:

    [如果你] 在&lt;key&gt; 上设置inverse="false"not-null,NH3 及更高版本将只执行两次插入而不是insert-insert-update。

    【讨论】:

    • 我确实读过,但它并没有真正解释任何事情(也没有引用双向关联的讨论)。这个决定背后有理由吗?这是nhibernate的设计限制吗?它是一个错误吗?作为 nhibernate 的新手,根本不了解内部结构,这似乎应该是可能的..
    • 老实说,我不知道。它没有被 NHibernate 团队归类为错误,它只是 NH​​ibernate 如何持久化实体的副作用。我不会假装知道原因,但我想这与数据库和身份生成器无关。
    • 实际上如果在 NH3 及以上的键上设置 inverse="false" 和 not-null 将只执行两次插入而不是 insert-insert-update
    • 我不知道为什么,但如果我设置 .Not.KeyNullable().Not.Inverse() 插入按预期工作 - 设置外键,但后来 nhibernate 发出额外更新,即不需要:设置已经设置的外键...这是设计成这样的吗?
    • +1 VikciaR,同样的问题。使用有效外键正确插入,但仍会发生更新。
    【解决方案3】:

    NHibernate 这样做的原因是:
    当它保存细节时,它只知道细节知道的东西。因此,在后台发生的任何主引用都会被忽略。 只有在保存 master 时,它才会看到关系并使用 master 的 id 更新集合的元素。
    从面向对象的角度来看,这是合乎逻辑的。然而,从储蓄的角度来看,这不太合乎逻辑。我想您总是可以提交错误报告,或者查看它是否可能已经提交并要求他们进行更改。但我想他们有其特定的(设计/领域)原因。

    【讨论】:

      猜你喜欢
      • 2014-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多