[ActiveRecord] 之六:继承

 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 = "班主任"
}




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值