流利的休眠 HasOne WithForeignKey 不起作用

Posted

技术标签:

【中文标题】流利的休眠 HasOne WithForeignKey 不起作用【英文标题】:fluent nhibernate HasOne WithForeignKey not working 【发布时间】:2010-10-13 05:17:33 【问题描述】:

每当我加载一个 Task 类时,Document 属性始终为 null,尽管 db 中有数据。

任务类:

public class Task

    public virtual Document Document  get; set; 

AutoPersistenceModel 的任务映射覆盖:

public void Override(AutoMap<Task> mapping)

    mapping.HasOne(x => x.Document)
        .WithForeignKey("Task_Id");

正如您所见,NHProf 所说的正在运行,连接条件错误,WithForeignKey 似乎没有生效。事实上,我可以在上面的代码中写任何字符串,它没有任何区别。

FROM   [Task] this_
    left outer join [Document] document2_
    on this_.Id = document2_.Id

应该是:

FROM   [Task] this_
    left outer join [Document] document2_
    on this_.Id = document2_.Task_Id

如果我破解数据库中的数据以使 ids 匹配,则加载数据,但显然这是不正确的 - 但至少它证明它加载了数据。

编辑:在流畅的 nhib 源中翻找 XML 会产生这样的结果:

<one-to-one foreign-key="Task_Id" cascade="all" name="Document" class="MyProject.Document, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 

编辑:这是架构:

CREATE TABLE [dbo].[Document](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Task_Id] [int] NOT NULL,

CREATE TABLE [dbo].[Task](
[Id] [int] IDENTITY(1,1) NOT NULL,

有人有什么想法吗?

谢谢

安德鲁

【问题讨论】:

【参考方案1】:

我试过这个解决方案:

就在文档中:

mapping.HasOne(x => x.Task).ForeignKey("Task_ID").Constrained().Cascade.All();

【讨论】:

【参考方案2】:

我一直在为同样的 Has One 问题苦苦挣扎,终于发现这行得通:

public class ParentMap : ClassMap<Parent>

    public ParentMap()
    
        Id(x => x.Id);
        HasOne(s => s.Child).Cascade.All();
    


 public class ChildMap : ClassMap<Model.Child>

    public ChildMap()
    
        Id(x => x.Id);
        HasOne(s => s.Parent).Constrained().ForeignKey();           
    

【讨论】:

两个表中的compositeid怎么办?【参考方案3】:

我今天遇到了同样的问题。我相信诀窍不是将 .ForeignKey(...) 与 .HasOne 映射一起使用,而是使用 .PropertyRef(...) 。以下是我如何定义组织(父)与其管理员(子)之间的一对一关系:

HasOne(x => x.Admin).PropertyRef(r => r.Organisation).Cascade.All();

管理员使用其外键对组织进行简单引用:

References(x => x.Organisation, "ORAD_FK_ORGANISATION").Not.Nullable();

在检索组织时,这将加载正确的管理员记录,并正确地级联更新和删除。

【讨论】:

似乎完美的答案是这个和 Chris Shaffer 的答案的结合。这个答案提供了一个使用 Fluent NHibernate 的工作实现,而 Chris Shaffer 提供了一些关于为什么初始实现不起作用的“理论”。 也为我工作,非常感谢。但是 HasOne().ForeignKey() 是什么? +1 但我必须将引用写为 References(x => x.Organisation).ForeignKey("ORAD_FK_ORGANISATION").Not.Nullable();因为它将外键名称作为组织的列名【参考方案4】:

我认为这里的问题是“HasOne”约定意味着您指向另一件事(说“多对一”/“一对一”的标准关系方式);通过将 Task_ID 放在文档上,实际关系是 HasMany,但您有某种隐含的理解,即每个任务只会有一个文档。

抱歉 - 我不知道如何解决这个问题,但我有兴趣了解解决方案是什么(我不使用 NHibernate 或 Fluent NHibernate,但我一直在研究它以供将来使用)。一个解决方案(来自一个几乎没有想法的人)是让 Documents 成为 Task 上的一个集合,然后提供一个 Document 属性,该属性返回集合中的第一个(使用隐藏 Documents 属性的界面,因此没有人认为他们可以添加新项目)。

查看文档并考虑 eulerfx 的答案,也许方法类似于:

References(x => x.Document)
    .TheColumnNameIs("ID")
    .PropertyRef(d => d.Task_ID);

编辑:这个答案有适当的解决方案:正确的路径是更新数据库模式以匹配代码的意图。这意味着将 DocumentID 添加到 Task 表中,因此 Task 和 Document 之间存在多对一的关系。如果无法更改架构,References() 将是合适的解决方案。

【讨论】:

我同意这种可能性,但为什么 Task_Id 没有在任何地方呈现? (即使它是错误的,因此会导致异常 - 但它不会) 这确实有效,但这意味着我需要 Document 上的 Task_id 属性,我宁愿没有。虽然现在可以工作,但谢谢【参考方案5】:

正如 eulerfx 指出的那样,

表格结构表明一个任务可能有多个文档

克里斯说:

通过将 Task_ID 放在文档上,实际关系是 HasMany,但您有某种隐含的理解,即每个任务只有一个文档。

这当然是正确的,所以我把它反转了,所以 Task 有一个可为空的 Document_Id。

感谢两位的帮助!

我投了一枚硬币以获得接受的答案,如果我能同时勾选我会的!

【讨论】:

嘿,安德鲁,PLN 的答案是肯定的。我会说,通过重新做数据库,你实际上做了正确的事情。但有时您无法更改数据库,而这正是 Fluent Mappings 真正大放异彩的地方。 HasOne 就是这样一个功能,你和我都错误地使用了它。 PLN 指出了使用它的正确方法......我的 2 美分【参考方案6】:

你应该使用:

参考(x => x.Document, "DocumentIdColumnOnTask")

【讨论】:

tblDocument 有 Task_Id,而不是 tblTask​​ 有 Document_Id 哦,好吧,错过了那部分。然后我想在任务表上有一个 docID 是最有意义的。否则表结构表明一个任务可能有多个文档。 是的,我想是的。这是有原因的,但我不记得为什么。我会考虑并考虑扭转它。 ta

以上是关于流利的休眠 HasOne WithForeignKey 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

nhibernate中的HasOne和References有啥区别?

Grails GORM 组合还是 hasOne?

Laravel 中 BelongsTo 和 HasOne 有啥区别

HasOne 和 HasMany 用于同一张表 cakephp

Sequelize ORM中HasOne和BelongsTo的区别

Sequelize 关联 hasOne,belongsTo