【问题标题】:How to map this legacy table with NHibernate (Fluent)?如何用 NHibernate (Fluent) 映射这个遗留表?
【发布时间】:2010-12-25 17:00:26
【问题描述】:

NHibernate 新手。不知如何映射这个遗留表。

CREATE TABLE [dbo].[CmnAddress](
[addressId] [int] NOT NULL,
[objectType] [varchar](63) NULL,
[objectId] [int] NULL,
[addressType] [varchar](7) NULL,
[recordStatus] [char](1) NULL,
[fromDate] [int] NULL,
[toDate] [int] NULL,
[onStreet] [varchar](254) NULL,
[atStreet] [varchar](254) NULL,
[unit] [varchar](30) NULL,
[city] [varchar](254) NULL,
[state] [varchar](30) NULL,
[zipCode] [varchar](30) NULL,
)

还有一个“CmnPerson”表,我已映射到 Person 类。我需要 Person 类包含地址列表,其中 objectType 列包含“CmnPerson”,objectId 字段与我的 Person.Id (“CmnPerson.personId”) 字段匹配。

我稍后还必须创建一个 Contact 类,该类还包含一个地址列表,其中 objectType 列包含“CmnContact”。

我很难确定是否应该使用 Any 映射或 class-hierarchy-per-table 并区分子列?或者如果其中任何一个都可以满足我的需求。

谁能告诉我如何映射这个地址类?流利的配置会更好。

添加信息:

以下类和映射几乎可以工作,但地址列表返回 CmnAddress 表中具有匹配 objectId 的所有行,而不管 objectType 字段的值如何。我想我可以在 Person.Addresses 的 HasMany 映射上使用 ApplyFilter,但这似乎不是“正确”的方式。

更多补充信息:我能够通过在调用 DiscriminateSubClassesOnColumn(...) 之后链接 AlwaysSelectWithValue() 来解决最后一个问题

public class Person
{
    public virtual int Id { get; private set; }
    public virtual string LastName { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string MiddleName { get; set; }
    public virtual string Gender { get; set; }

    public virtual IList<PassClient> PassClients { get; set; }
    public virtual IList<PersonAddress> Addresses { get; set; }
}

public class PersonMap : ClassMap<Person>
{
    public PersonMap() {
        Table("CmnPerson");
        Id(x => x.Id).Column("personId");
        Map(x => x.LastName);
        Map(x => x.FirstName);
        Map(x => x.MiddleName);
        Map(x => x.Gender);

        HasMany(x => x.PassClients).KeyColumn("personId");
        HasMany(x => x.Addresses).KeyColumn("objectId");
    }
}

abstract public class Address
{
    public virtual int Id { get; private set; }
    public virtual string StreetNo { get; set; }
    public virtual string OnStreet { get; set; }
    public virtual string Unit { get; set; }
    public virtual string City { get; set; }
    public virtual string State { get; set; }
    public virtual string ZipCode { get; set; }
}

public class PersonAddress : Address { 
    public virtual Person Person { get; set; }
}

public class AddressMap : ClassMap<Address>
{
    public AddressMap() {
        Table("CmnAddress");

        Id(x => x.Id).Column("addressId");
        Map(x => x.StreetNo);
        Map(x => x.OnStreet);
        Map(x => x.Unit);
        Map(x => x.City);
        Map(x => x.State);
        Map(x => x.ZipCode);

        DiscriminateSubClassesOnColumn("objectType").AlwaysSelectWithValue();
    }
}

public class PersonAddressMap : SubclassMap<PersonAddress>
{
  public PersonAddressMap() {
        DiscriminatorValue("CmnPerson");

        References(x => x.Person).Column("objectId");
  }
}

【问题讨论】:

    标签: nhibernate fluent-nhibernate mapping hierarchy legacy


    【解决方案1】:

    当它是多关系时,您不能使用 Any-mapping。当地址可以指向不同类型的对象时,可以使用它——比如一个人、一个订单或其他不相关的东西。

    要映射层次结构,您可以这样做:

    public class CmnAddressMap : ClassMap<CmnAddress>
    {
        public CmnAddressMap()
        {
            Id(x => x.addressId);
            Map(x => x...);
    
            DiscriminateSubClassesOnColumn("objectType");
        }
    }
    
    public class PersonAdressMap : SubclassMap<PersonAddress>
    {
        public PersonAdressMap()
        {
            DiscriminatorValue("objectType1");
        }
    }
    
    public class ContactAdressMap : SubclassMap<ContactAddress>
    {
        public ContactAdressMap()
        {
            DiscriminatorValue("objectType2");
        }
    }
    

    有一个包含所有字段的抽象 CmnAddress(例如映射 CmnAdressMap 中的所有字段)和两个名为 PersonAddress 和 ContactAddress 的子类。

    然后这个人应该有一个像 IList 这样的集合,它应该用 HasMany 映射。你应该完成了。

    【讨论】:

    • 我刚刚得到了完全相同的答案——刚刚完成了测试。它确实编译并运行,但 Person.Addresses 列表返回 CmnAddress 表中具有匹配 id 值的所有行,而不管区分列中的值如何。关于如何解决这个问题的任何想法?
    • 答案是在 DiscriminateSubClassesOnColumn(...) 调用之后链接 AlwaysSelectWithValue() 调用。或者至少它似乎有预期的结果。
    • 抱歉我的回复晚了。这很奇怪。我刚刚对你的场景进行了测试,我不需要指定 AlwaysSelectWithValue()。
    • 哦。现在我看到了你的新信息。您在地址表中是否有没有鉴别器或鉴别器值未映射到子类的行?
    • 我确实有没有映射到子类的鉴别器值,这就是我必须指定 AlwaysSelectWithValue() 的原因。
    【解决方案2】:

    对不起,我不熟悉流畅的映射,但是,一种方法是:

    • 创建一个 Address 抽象类,其属性对应于表中除 objectType 之外的所有列
    • 创建一个扩展 AddressPersonAddress
    • 创建一个扩展 Address

    • ContactAddress
    • 以正常方式将 CmnAddress 的所有列映射到 Address 类的属性,您声明的 objectType 除外作为鉴别列

    • PersonAddress 映射为 Address 的子类,区分值为“CmnPerson”
    • ContactAddress 映射为 Address 的子类,鉴别器值为“CmnContact”

    在代码中,您的 Person 类将包含一个 PersonAddresses 列表,而您的 Contact 类将包含一个 ContactAddresses

    列表

    【讨论】:

      【解决方案3】:

      地址类

      public class Address
      {
          public virtual int Id { get; set; }
          public virtual Person Person { get; set; }
          // etc.
      }
      

      人物类

      public class Person
      {
          public Person()
          {
              Addresses = new List<Address>();
          }
      
          public virtual int Id { get; set; }
          // etc.
          public virtual IList<Address> Addresses { get; set; }
      }
      

      地址映射

      public class AddressMap : ClassMap<Address>
      {
          public AddressMap()
          {
              Table("CmnAddress");
              Id(x => x.Id).Column("addressId");
              // etc.
              References(x => x.Person);
          }
      }
      

      要区分 Address => Person 和 Address => Contact 之间的区别,您需要阅读 NHibernate 的多态性并根据列区分子类。

      【讨论】:

      • 这是我无法理解的区别部分。我不确定是否需要创建从 Address 继承的子类——比如 PersonsAddress 和 ContactsAddress。我也不完全清楚将字符串值“CmnPerson”和“CmnContact”映射到适当的地址子类的 Fluent 方法。
      猜你喜欢
      • 2011-05-22
      • 1970-01-01
      • 2011-04-10
      • 1970-01-01
      • 2012-02-17
      • 1970-01-01
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多