代码之家  ›  专栏  ›  技术社区  ›  James Bender

在Fluent NHibernate中保存基类列表

  •  1
  • James Bender  · 技术社区  · 15 年前

    我是一个有点流利的无纤维新生儿,所以原谅我,这很容易,我只是错过了。

    我有一个客户和用户的类层次结构,它们都继承自个人。客户和用户都有自己的表和映射,一切都很好地工作。

    我的问题是,客户和用户需要一个联系人列表,该列表的类型为ilist。因此,客户和用户都会有一个联系人列表,其中可以包含客户和用户的组合。

    我有点纠结于如何绘制这张地图,我会很感激你提供的任何建议。

    谢谢!

    2 回复  |  直到 15 年前
        1
  •  1
  •   mhenrixon    15 年前

    我相信你需要一个 IList<Person> Contacts {get;set;} 以及一个类型(鉴别器),以便您知道将其强制转换为什么。也许是黑客,但我就是这么做的。

    编辑: 假设您的实体如下所示。

    public abstract class Person
    {
        public virtual int Id { get; private set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
    }
    
    public class Customer : Person
    {
        public virtual string Foo { get; set; }
    }
    
    public class Contact : Person
    {
        public virtual string Bar { get; set; }
    }
    

    解决问题的简单方法是使用鉴别器,并将所有内容移到同一个表中。此映射可能如下所示:

    public class PersonMap : ClassMap<Person>
    {
        public PersonMap()
        {
            Id(x => x.Id).GeneratedBy.Native();
            Map(x => x.FirstName).Length(40);
            Map(x => x.LastName).Length(100);
            DiscriminateSubClassesOnColumn("TypeOfPerson");
        }
    }
    
    public class CustomerMap : SubclassMap<Customer>
    {
        public CustomerMap()
        {
            Map(x => x.Foo);
        }
    }
    
    public class ContactMap : SubclassMap<Contact>
    {
        public ContactMap()
        {
            Map(x => x.Bar);
        }
    }
    

    如果基于该模型生成架构,则最终会得到:

    create table [Person] (
      Id                 INT   IDENTITY   NOT NULL,
      BillingDetailsType NVARCHAR(255)   not null,
      FirstName          NVARCHAR(40)   null,
      LastName           NVARCHAR(100)   null,
      Foo                NVARCHAR(255)   null,
      Bar                NVARCHAR(255)   null,
        primary key ( Id ))
    

    我知道这可能并不理想,所以如果你的老板(像我的老板)是一个拒绝让数据库处于这种状态的数据库专家的话。你需要做的就是移除 DiscriminateSubClassesOnColumn("TypeOfPerson"); 如果您从代码中生成模式,那么您应该以如下的表结构结束:

    -- statement #1
    create table [Person] (
      Id        INT   IDENTITY   NOT NULL,
      FirstName NVARCHAR(40)   null,
      LastName  NVARCHAR(100)   null,
        primary key ( Id ))
    
    -- statement #2
    create table [Customer] (
      Person_id INT   not null,
      Foo       NVARCHAR(255)   null,
        primary key ( Person_id ))
    
    -- statement #3
    create table [Contact] (
      Person_id INT   not null,
      Bar       NVARCHAR(255)   null,
        primary key ( Person_id ))
    
    -- statement #4
    alter table [Customer]
     add constraint FKFE9A39C0B58BA2A5 foreign key ( Person_id ) references [Person]
    

    使用最后一个模式,您需要找出一种方法来确定所选人员的真正子类,如果您需要 IList<Person> 但我相信你能理解。:)希望这有帮助!

        2
  •  0
  •   Marek Tihkan    15 年前

    我是按派对模式做的。这样,你的抽象就一直是聚会:

    public abstract class Party
    {
         private IList<Party> _contacts = new List<Party>();
    
         public int Id {get; set;}
         public abstract string DisplayName { get; }
         public IEnumerable<Party> Contacts { get { return _contacts; } }  
    }
    
    public class Person 
    {
         public string FirstName {get; set;}
         public string LastName {get; set;}
    
         public override string DisplayName 
         {
             get { return FirstName + " " + LastName; }
         }
    }
    
    public class Organization
    {
         public string Name {get; set;}
    
         public override string DisplayName 
         {
             get { return Name; }
         }
    }
    

    对于映射,有两种可能的策略:每个继承树一个表;每个类一个表。

    public class PartyMap : ClassMap<Party>
    {
        public PartyMap()
        {
            Id(x => x.Id).GeneratedBy.Native();
            HasManyToMany(x => x.Contacts).Access.CamelCaseField(Prefix.Underscore);
        }
    }
    
    public class PersonMap : JoinedSubClassPart<Person>
    {
        public PersonMap()
        {
            Map(x => x.FirstName).Length(40);
            Map(x => x.LastName).Length(100);
        }
    }
    
    public class OrganizationMap : JoinedSubClassPart<Organization>
    {
        public OrganizationMap()
        {
            Map(x => x.Name).Length(40);
        }
    }
    

    应该创建4个表:Party、Person、Organization和Contact