单向一对多关系的 NHibernate 配置

发布于 2024-10-08 08:42:42 字数 2202 浏览 0 评论 0原文

我正在尝试建立如下关系。每个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

Detail 为:

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

我真的不关心从 Detail 回到 Master 的链接——换句话说,Detail 对象本身对我的域层来说并不感兴趣。它们总是通过其主对象进行访问。

使用这样的代码:

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

这非常有效,除了 中概述的疯狂限制之外这篇文章:NHibernate 执行 INSERT 并将 Detail.MasterId 首先设置为 NULL,然后执行 UPDATE 将其设置为真实的 MasterId。

实际上,我不希望详细信息条目具有 NULL MasterId,因此如果我将 MasterId 字段设置为 NOT NULL,则 INSERT 到 Detail 将失败,因为正如我所说,NHibernate 正在尝试输入 MasterId = NULL。

我想我的问题归结为:

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

有没有办法让 Nhibernate 将正确的 MasterId 放入初始 INSERT 中,而不是随后运行 UPDATE?这个设计决定有什么理由吗? ——我很难理解为什么要这样做。

I'm trying to set up a relationship as follows. Each Master item has one or more Detail items:

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

And Mappings:

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

The Master database table is:

masterId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL

and Detail is:

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

I don't really care to have a link from Detail back to Master -- in otherwords, Detail objects on their own are just not interesting to my domain layer. They will always be accessed via their Master object.

Using code like this:

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 works great, except for a crazy limitation outlined in this post: NHibernate does an INSERT and puts Detail.MasterId as NULL first, then does an UPDATE to set it to the real MasterId.

Really, I don't want Detail entries with NULL MasterIds, so if I set the MasterId field to NOT NULL, the INSERT to Detail will fail, because as I said NHibernate is trying to put in MasterId = NULL.

I guess my question boils down to this:

How can I get the above code sample to work with my existing domain model (eg, without adding a Detail.Master property), and the Detail.MasterId field in the database set to NOT NULL?

Is there a way to get Nhibernate to just put the correct MasterId in the initial INSERT, rather than running an UPDATE afterwards? Is there rationale somewhere for this design decision? -- I'm struggling to see why it would be done this way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遇到 2024-10-15 08:42:42

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

FluentNHibernate 代码片段:

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

NH3 and above allow to correct save entities in case of uni-directional one-to-many mapping without annoying save null-save-update cycle, if you set both not-null="true" on <key> and inverse="false" on <one-to-many>

FluentNHibernate code snippet for that:

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();
    }
}
我早已燃尽 2024-10-15 08:42:42

你不能。引用我的回答中的链接您链接到的另一个问题:

非常重要的注意事项:如果 关联的 列声明为 NOT NULL ,NHibernate在创建或更新关联时可能会导致约束违规。为了防止出现此问题,您必须使用双向关联,并将多值端(集合或包)标记为 inverse="true"。请参阅本章后面关于双向关联的讨论。

编辑: 正如 Hazzik 正确指出的那样,这在 NHibernate 3 及更高版本中已发生变化。遗憾的是,文档尚未更新,因此 Hazzik 如下:

[如果]在上设置inverse="false"not-null,NH3及以上将仅执行两次插入代替 insert-insert-update。

You can't. To quote the link from my answer on the other question you linked to:

Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

Edit: as Hazzik has rightly pointed out, this has changed in NHibernate 3 and above. The docs sadly haven't been updated, so here's Hazzik:

[If you] set inverse="false" and not-null on <key>, NH3 and above will perform only two inserts insead of insert-insert-update.

叹倦 2024-10-15 08:42:42

NHibernate 这样做的原因是:
当它保存详细信息时,它只知道该详细信息所知道的内容。因此,在后台发生的任何主引用都将被忽略。
仅当保存 master 时,它才会看到关系并使用 master 的 id 更新集合的元素。

从面向对象的角度来看,这是合乎逻辑的。然而,从节省的角度来看,这有点不合逻辑。我想您始终可以提交错误报告,或者查看是否已经提交并要求他们进行更改。但我认为他们有其特定的(设计/领域)原因。

The reason NHibernate does it this way is because:
When it saves the detail it only knows about the stuff the detail knows about. So any master references which happen in the background are ignored.
Only when the master is saved it sees the relation and updates the elements of the collection with the id of the master.

Which is from an object oriented point of view logical. However from a saving point-of-view is slightly less logical. I suppose you can always file a bug report, or look if it might have been filed already and ask them to change it. But I suppose they have their specific (design/domain) reasons.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文