http://www.rainsts.net/article.asp?id=244
ActiveRecord 支持继承体系,我们看看几种不同的实现方式。

1. 无关联继承
public class Person
{
  private int id;

  [PrimaryKey(PrimaryKeyType.Identity)]
  public int Id
  {
    get { return id; }
    set { id = value; }
  }

  private string name;

  [Property(NotNull=true)]
  public string Name
  {
    get { return name; }
    set { name = value; }
  }
}

[ActiveRecord]
public class Student : Person
{
  private int grade;

  [Property]
  public int Grade
  {
    get { return grade; }
    set { grade = value; }
  }
}

[ActiveRecord]
public class Teacher : Person
{
  private string job;

  [Property]
  public string Job
  {
    get { return job; }
    set { job = value; }
  }
}

调用 ActiveRecordStarter.CreateSchema(); ,你会发现数据库里面分别生成了 Student 和 Teacher 数据表,每个表都拥有基类(Person)的字段,相互没有关联。这种继承方式下,我们无法通过 Find(typeof(Person)) 来返回所有人(Student & Teacher)。严格来说,我们根本无法调用此方法,因为我们不能为 Person 添加 ActiveRecordAttribute。

此方式仅仅是为了代码重用而已,并没有业务上的关联。

== 数据表结构 ==
Student Table
{
  Id
  Name
  Grade
}

Teacher Table
{
  Id
  Name
  Job
}

执行插入对象测试代码
Student s = new Student();
s.Name = "student1";
s.Grade = 2;
ActiveRecordMediator.Create(s);

Teacher t = new Teacher();
t.Name = "teacher1";
t.Job = "班主任";
ActiveRecordMediator.Create(t);

结果
Student Table
{
  Id = 1
  Name = "student1"
  Grade = 2
}

Teacher Table
{
  Id = 1
  Name = "teacher1"
  Job = "班主任"
}

2. 单表关联继承

我们使用 ActiveRecordAttribute 内置属性更改上面的例子,使其成为关联继承。
[ActiveRecord(DiscriminatorColumn = "Type", DiscriminatorType = "String", DiscriminatorValue = "Person")]
public class Person
{
  private int id;

  [PrimaryKey(PrimaryKeyType.Identity)]
  public int Id
  {
    get { return id; }
    set { id = value; }
  }

  private string name;

  [Property(NotNull=true)]
  public string Name
  {
    get { return name; }
    set { name = value; }
  }
}

[ActiveRecord(DiscriminatorValue = "Student")]
public class Student : Person
{
  private int grade;

  [Property]
  public int Grade
  {
    get { return grade; }
    set { grade = value; }
  }
}

[ActiveRecord(DiscriminatorValue = "Teacher")]
public class Teacher : Person
{
  private string grade;

  [Property]
  public string Job
  {
    get { return grade; }
    set { grade = value; }
  }
}

你会发现数据库里面仅生成了一个Person表。

== 数据表结构 ==
Student Person
{
  Id
  Type // 由 Person[DiscriminatorColumn...] 特性生成!
  Name
  Grade
  Job
}

执行插入对象测试代码
结果
Person Table
{
  // Record 1-----------------
  Id = 1
  Type = "Student"
  Name = "student1"
  Grade = 2
  Job = <NULL>

  // Record 2-----------------
  Id = 2
  Type = "Teacher"
  Name = "teacher1"
  Grade = <NULL>
  Job = "办主任"
}

在基类定义一个 DiscriminatorColumn 特性,子类通过写入不同的 DiscriminatorValue 来达到区分不同子类型的目的。

这种方式解决了多态查询的问题,但当子类新增属性较多,而且多个子类属性差别较大的情况下,数据库空间浪费会比较严重。同时由于对于不属于当前类的数据库字段插入NULL,可能会造成插入时发生错误,触发异常(比如我们将 Teacher.Job 的特性改为 Property(NotNull=true),那么我们保存Student对象到数据库时就会触发异常)。

我们对基类和子类进行查询测试
foreach Person p in (Person[])ActiveRecordMediator.FindAll(typeof(Person)))
{
  Console.WriteLine("Person {0}:{1}", p.Id, p.Name);
}

foreach (Student p2 in (Student[])ActiveRecordMediator.FindAll(typeof(Student)))
{
  Console.WriteLine("Student {0}:{1}", p2.Id, p2.Name);
}

foreach (Teacher p3 in (Teacher[])ActiveRecordMediator.FindAll(typeof(Teacher)))
{
  Console.WriteLine("Teacher {0}:{1}", p3.Id, p3.Name);
}

输出
Person 1:student1
Person 2:teacher1
Student 1:student1
Teacher 2:teacher1

建议你继续往下看,或许下面的方式更适合你。

3. 多表关联继承
[ActiveRecord, JoinedBase]
public class Person
{
  private int id;

  [PrimaryKey(PrimaryKeyType.Identity)]
  public int Id
  {
    get { return id; }
    set { id = value; }
  }

  private string name;

  [Property(NotNull=true)]
  public string Name
  {
    get { return name; }
    set { name = value; }
  }
}

[ActiveRecord]
public class Student : Person
{
  [JoinedKey("Id")]
  public int StudentId
  {
    get { return base.Id; }
    set { base.Id= value; }
  }
    
  private int grade;

  [Property]
  public int Grade
  {
    get { return grade; }
    set { grade = value; }
  }
}

[ActiveRecord]
public class Teacher : Person
{
  [JoinedKey("Id")]
  public int TeacherId
  {
    get { return base.Id; }
    set { base.Id= value; }
  }
    
  private string grade;

  [Property]
  public string Job
  {
    get { return grade; }
    set { grade = value; }
  }
}

我们注意到为 Person 添加了 ActiveRecordAttribute 和 JoinedBaseAttribute 特性,同时为子类 Student 和 Teacher 添加了一个附加了 JoinedKeyAttribute 的 Id 字段。此继承模式会分别生成 Person、Student 和 Teacher 三个数据表。Person 存储了基类的所有字段,子类表仅包含子类增加的属性和Id映射字段。此继承方式下,我们查找 Person 时,会同时返回 Student 和 Teacher记录。

== 数据表结构 ==
Person Table
{
  Id
  Name
}

Student Table
{
  StudentId
  Grade
}

Teacher Table
{
  TeacherId
  Job
}

执行插入对象测试代码
结果
Person Table
{
  // Record 1---
  Id = 1
  Name = "student1"

  // Record 1---
  Id = 2
  Name = "teacher1"
}

Student Table
{
  Id = 1
  Grade = 2
}

Teacher Table
{
  Id = 2
  Job = "班主任"
}

-----------------

附:本文所有演示代码使用 2006-01-01 发布的 Castle ActiveRecord Beta3 版本。
Castle ActiveRecord 在发布 1.0 版本前可能有很多较大的变化,如演示代码无法编译,建议您参考最新版本的相关文档。
[最后修改由 yuhen, 于 2006-09-12 14:02:47]
posted on 2008-01-23 07:21  JerryZhao  阅读(625)  评论(0编辑  收藏  举报