Fluent NHibernate - 如何将外键列映射为属性

Posted

技术标签:

【中文标题】Fluent NHibernate - 如何将外键列映射为属性【英文标题】:Fluent NHibernate - How to map the foreign key column as a property 【发布时间】:2009-04-01 23:16:39 【问题描述】:

我确信这是一个直截了当的问题,但请考虑以下问题: 我在公司和部门之间有如下参考:

public class Company 
    public Guid ID  get; set; 
    public Sector Sector  get; set; 
    public Guid SectorID  get; set; 


public class Sector 
    public Guid ID  get; set; 
    public string Name  get; set; 

好的。我想要的是我去后要填充的 Company 对象的 SectorID:

(new Company()).Sector = new Sector()  Name="asdf" 

然后冲洗一下。

我正在使用的映射在 Company 表中的数据库中创建了一个名为 Sector_Id 的附加列,但这不能作为 Company 的属性使用。我想要填充 SectorID 属性。

我目前在 CompanyMap 中使用的映射是

References(c => c.Sector).Cascade.All();

有人有什么想法吗?


感谢您的回复。 可悲的是,如果我执行第二个选项(将列的列名设置为与属性相同,或者设置 Map(x => x.SectorID, "Sector_Id"),那么我会收到错误消息:

System.IndexOutOfRangeException:此 SqlParameterCollection 的索引 7 无效,Count=7。

我可能必须做第一个选项,但我担心当您调用 SectorID get 时会触发一个额外的查询,因为它将 Sector 本身从数据库中取出(除非它是急切加载的,这有点麻烦)。

我很惊讶没有一个简单的答案。


哇! 如果我使用

public virtual Guid SectorID

    get  return Sector.ID;
   

然后 nhibernate 足够聪明,知道组织查询中的 Sector_id 列实际上与 Sector.ID 相同,并且它在后台返回它。即使您延迟加载,它也不会发送额外的查询。我印象深刻!


作为后续......似乎休眠并不是真正编写能够映射对象中的外键列。尽管这在 Web 前端可能有点痛苦,但它是有道理的,因为这实际上是一个持久性问题,而不是真正的对象问题。 我正在使用 asp.net MVC 并编写了一个自定义模型绑定器,它将采用名称联系人(而不是 ContactID)的输入框,使用 texbox 中的 ID 新建一个新联系人,然后将其应用于模型的属性。这解决了 Web 前端下拉列表的问题。如果有人感兴趣,将发布代码。

【问题讨论】:

【参考方案1】:

这很容易通过公式属性完成。

public class Company 
  public virtual Guid Id  get; set; 
  public virtual Guid? SectorId  get; set; 
  public virtual Sector Sector  get; set; 


public class CompanyMap : ClassMap<Company> 
  public CompanyMap() 
    Id(x => x.Id); // Maps to a column named "Id"
    References(x => x.Sector); // Maps to a column named "Sector_id", unless you change the NHibernate default mapping rules.
    Map(x => x.SectorId).Formula("[Sector_id]");
      

这应该完全按照您的意愿行事。当Company 是新的时,SectorId 将为空;从数据库中获取Company 时,SectorId 将填充给定的公式值。 SectorId 作为属性公开,这使得它非常适合处理 web 下拉列表等。保存时,您仍然需要绑定“真实”关联。假设SectorId在表单中被选中...

using (var txn = session.BeginTransaction()) 
  // Set the FK reference.
  company.Sector = session.Load<Sector>(company.SectorId);
  // Save the new record.
  session.Save(company);
  // Commit the transaction.
  txn.Commit();

【讨论】:

我给你积分来解决我遇到的错误,但这似乎完全不直观。如果 NHibernate 无法处理同时具有 FK ID 和关联的对象实例作为属性的常见场景,这似乎是一个设计问题。【参考方案2】:

史蒂夫,你不需要 POCO 类中的 ForeignKey 属性。

例如,如果您将尝试获取文章作者的 ID,则不会执行连接选择。

var authorID = Article.Author.ID

【讨论】:

【参考方案3】:

两个想法:首先,这样的事情不会实现你想要的吗?

public class Company 
    public Guid ID  get; set; 
    public Sector Sector  get; set; 
    public Guid SectorID 
        get  return Section.ID; 
        // Really not sure what behavior your setter should have here; Maybe it shouldn't even have one?
        set  Sector = new Sector  ID = value ; 
    

其次,当您说映射在数据库中创建了一个名为 Sector_Id 的列时,是不是除了您创建的名为 SectorID 的列之外?如果是这样,您可以更改列名,使其使用正确的名称(here's the documentation for mappings,请参阅“指定列名”下方的几个标题)。

另外,您是否在映射 SectorID 属性(例如“Map(x => x.SectorID, "Sector_Id")”)?

【讨论】:

以上是关于Fluent NHibernate - 如何将外键列映射为属性的主要内容,如果未能解决你的问题,请参考以下文章

Fluent NHibernate 主键约束命名约定

如何使用 Fluent 设置 NHibernate.Burrow?

Laravel - 如何将外键用于具有识别外键的表?

如何将外键添加到现有表?

如何使用 Fluent-NHibernate 和 MySQL 指定自动递增 (int) 标识列

如何在 Fluent NHibernate ClassMap 类中指定表名?