NHibernate 将 1 个对象映射到 2 个表

Posted

技术标签:

【中文标题】NHibernate 将 1 个对象映射到 2 个表【英文标题】:NHibernate Mapping 1 Object To 2 Tables 【发布时间】:2011-09-06 03:48:58 【问题描述】:

我们想在我们的应用程序中使用 NHibernate 作为我们的持久层。我们还使用 Fluent NHibernate 进行映射。

我们从第 3 方获取 Person 数据,我们需要将数据保存到我们的数据库中。在代码中将所有属性都放在一个对象上效果更好,但将数据保存到数据库中的 2 个表中更有意义。

我们的对象如下所示:

public class Person

    public virtual long VersionNumber  get; set; 
    public virtual string FirstName  get; set; 
    public virtual string LastName  get; set; 
    public virtual string IdentificationNumber  get; set; 

我们的数据库表如下所示:

CREATE TABLE PersonVersion (
    [PK] VersionNumber bigint NOT NULL,
    [FK] PersonDemographicsId int NOT NULL
)
CREATE TABLE PersonDemographics (
    [PK] PersonDemographicsId int NOT NULL,
    IdentificationNumber nvarchar(9) NOT NULL,
    FirstName nvarchar(100) NOT NULL,
    LastName nvarchar(100) NOT NULL
)

当我们收到新数据时,版本号可能会发生变化,但其他人口统计数据可能相同。我们需要 NHibernate 做的是将新记录保存到链接到现有 PersonDemographics 记录的 PersonVersion 表中。如果人口统计数据发生了变化,那么我们将在两个表中创建一条新记录。但大多数情况下,一旦我们下载了初始数据,人口统计数据就不会像版本号那样频繁变化。我们需要跟踪所有版本号,因此有必要创建一个新的PersonVersion 记录。

我们将如何使用 NHibernate 和使用 Fluent NHibernate 的映射来完成此任务?

另外,如您所见,我们的 Person 对象目前没有PersonDemographicsId,因为我们的应用程序根本不需要它;它只是数据库中需要的表关系的ID。为了在 NHibernate 中正确映射它,我们是否必须在 Person 对象上添加 PersonDemographicsId 属性?

感谢您的帮助!

【问题讨论】:

除非 PersonDemographics 有一些您没有显示的大量 BLOB 数据,否则我建议您考虑将版本号展平到该表中。在每个请求上加入和/或子查询的成本加上重建历史状态的复杂性(我什至看不到您描述的模型如何实现)可能超过通过保留更少数据获得的任何小好处. 是的,我确实遗漏了一些属性,但都是简单类型;没有 BLOB 数据。我们决定使用这个模型的原因是因为我们将要处理的记录数量。每年,我们的数据库中都会有 600,000 到 1,000,000 个不同的人,每个人全年都有多个版本。大多数时候人口统计数据不会改变,但有时会改变。如果我们将这些表扁平化为 1,我们将拥有大量重复数据。从存储的角度来看,仅仅为了版本更改而不断复制人口统计数据是没有意义的。 Fluent NHibernate - Map 2 tables to one class 的可能重复项 【参考方案1】:

这篇文章http://ayende.com/blog/2327/multi-table-entities-in-nhibernate 解释了一种将单个类映射到数据库中的两个表的方法。

【讨论】:

我知道如何将 1 个对象映射到 2 个表。那不是问题。问题是它是如何保存到每个表中的。大多数时候,我需要在 1 个表中插入一条新记录并引用另一个表中的现有记录。但是有时我需要在两个表中插入一条新记录。请重新阅读整个问题以完全理解我想要做什么。【参考方案2】:

只是一个想法,可能需要调整

public class Person

    public virtual int Id  get; set; 

    internal protected virtual IList<long> VersionNumbers  get; set; 
    public virtual long VersionNumber 
       get  return VersionNumbers[VersionNumbers.Count - 1]; 
       set  VersionNumbers.Add(value); 
    
    public virtual string FirstName  get; set; 
    public virtual string LastName  get; set; 
    public virtual string IdentificationNumber  get; set; 


public class PersonMap : ClassMap<Person>

    public PersonMap()
    
        Table("PersonDemographics");
        Id(p => p.Id, "PersonDemographicsId").GeneratedBy.Assigned();
        Map(p => p.FirstName);
        Map(p => p.LastName);
        Map(p => p.IdentificationNumber);

        HasMany(p => p.VersionRecord)
            .Table("PersonVersion")
            .KeyColumn("PersonDemographicsId")
            .Element("VersionNumber")
            .OrderBy("VersionNumber")
            .Cascade.All();
    

【讨论】:

以上是关于NHibernate 将 1 个对象映射到 2 个表的主要内容,如果未能解决你的问题,请参考以下文章

nhibernate 映射枚举对(键 - 值)

NHibernate 可以将 CLR“对象”类型映射到 SQL 类型吗?

MapStruct:将 2 个对象映射到第 3 个对象

NHibernate:映射具有属性的复杂值类型?

NHibernate 是不是支持使用复合 ID 将抽象类映射到不同的表?

NHibernate总结