在面向对象的设计中继承是少不了的,那么如何在AR里来设计有继承关系的实体类呢?查看相关文档并做了一些尝试,例子如下(例子很简陋,仅是单纯考虑继承的实现)。其中有理解错误的地方还肯请大家指正。
一、使用 subclass [ActiveRecord( " Entity " ), JoinedBase] public class Entity : ActiveRecordBase { private int id; private string name; public Entity() { } [PrimaryKey(PrimaryKeyType.Assigned, " id " )] public int Id { get { return id; } set { id = value; } } [Property] public string Name { get { return name; } set { name = value; } } public new static void DeleteAll() { ActiveRecordBase.DeleteAll( typeof (Entity)); } public new static Entity[] FindAll() { return (Entity[])ActiveRecordBase.FindAll( typeof (Entity)); } public new static Entity Find( int id) { return (Entity)ActiveRecordBase.FindByPrimaryKey( typeof (Entity), id); } } [ActiveRecord( " EntityCompany " )] public class CompanyEntity : Entity { private byte company_type; private int comp_id; [JoinedKey( " comp_id " )] public int CompId { get { return comp_id; } set { comp_id = value; } } [Property( " company_type " )] public byte CompanyType { get { return company_type; } set { company_type = value; } } public new static void DeleteAll() { ActiveRecordBase.DeleteAll( typeof (CompanyEntity)); } public new static CompanyEntity[] FindAll() { return (CompanyEntity[])ActiveRecordBase.FindAll( typeof (CompanyEntity)); } public new static CompanyEntity Find( int id) { return (CompanyEntity)ActiveRecordBase.FindByPrimaryKey( typeof (CompanyEntity), id); } } [ActiveRecord( " EntityPerson " )] public class PersonEntity : Entity { private int person_id; [JoinedKey( " person_id " )] public int PersonId { get { return person_id; } set { person_id = value; } } public new static void DeleteAll() { ActiveRecordBase.DeleteAll( typeof (PersonEntity)); } public new static PersonEntity[] FindAll() { return (PersonEntity[])ActiveRecordBase.FindAll( typeof (PersonEntity)); } public new static PersonEntity Find( int id) { return (PersonEntity)ActiveRecordBase.FindByPrimaryKey( typeof (PersonEntity), id); } }
这个例子中,首先在基类Entity的属性标签加上"JoinedBase"参数(表示为一个或多个subclass的父类),然后在子类CompanyEntity和PersonEntity中分别增加一个属性CompId和PersonId并打上"JoinedKey"属性标签(它们在数据表中体现为外键,通过它把子类与基类的表关联起来)。 这种方法会将基类映射到一张数据表,子类分别映射到单独的一张数据表(表里不包含基类的属性值,这些值都在基类映射的数据表中)。持久化子类的时候,相关信息分别保存到基类和子类映射的数据表中。测试一下: private void TestSubclass() { PersonEntity person = new PersonEntity(); person.Id = 500 ; person.Name = " Allen " ; person.Create(); CompanyEntity company = new CompanyEntity(); company.Id = 100 ; company.Name = " SomeName " ; company.Create(); Entity en = Entity.Find( 100 ); string str = en.ToString() + " , ID= " + en.Id + " , Name= " + en.Name; CompanyEntity comp = CompanyEntity.Find( 100 ); str += " \r\n " + comp.ToString() + " , ID= " + comp.Id.ToString() + " , CompId= " + comp.CompId.ToString() + " , Name= " + comp.Name; PersonEntity pers = PersonEntity.Find( 500 ); str += " \r\n " + pers.ToString() + " , ID= " + pers.Id.ToString() + " , PersonId= " + pers.PersonId.ToString() + " , Name= " + pers.Name; MessageBox.Show(str); }
显示结果:
xx.CompanyEntity, ID=100, Name=SomeNamexx.CompanyEntity, ID=100, CompId=0, Name=SomeNamexx.PersonEntity, ID=500, PersonId=0, Name=Allen这里很奇怪的是 CompId和PersonId 应该和 ID 是相同的值,但取出来却都是0。 不知道是为什么... 二、使用 Discriminator [ActiveRecord( " EntityBase " , DiscriminatorColumn = " type " , DiscriminatorType = " String " , DiscriminatorValue = " Entity " )] public abstract class EntityBase : ActiveRecordBase < EntityBase > { private int _id; private string _name; public EntityBase() { } public EntityBase( string name) { this ._name = name; } [PrimaryKey(PrimaryKeyType.Native, " id " )] public int ID { get { return _id; } set { _id = value; } } [Property( " name " )] public string Name { get { return _name; } set { _name = value; } } } [ActiveRecord(DiscriminatorValue = " blog " )] public class BlogEntity : EntityBase { private IList _posts; public BlogEntity() { this ._posts = new ArrayList(); } public BlogEntity( string name) : base (name) { } [HasMany( typeof (PostEntity), Table = " Entity " , ColumnKey = " post_of " , Cascade = ManyRelationCascadeEnum.All)] public IList Posts { get { return _posts; } set { _posts = value; } } public new static void DeleteAll() { ActiveRecordBase < BlogEntity > .DeleteAll(); } public new static BlogEntity[] FindAll() { return ActiveRecordBase < BlogEntity > .FindAll(); } public static BlogEntity Find( int id) { return ActiveRecordBase < BlogEntity > .Find(id); } public static BlogEntity TryFind( int id) { return ActiveRecordBase < BlogEntity > .TryFind(id); } } [ActiveRecord(DiscriminatorValue = " post " )] public class PostEntity : EntityBase { private BlogEntity _blog; public PostEntity() { } public PostEntity( string name) : base (name) { } [BelongsTo( " post_of " )] public BlogEntity Blog { get { return _blog; } set { _blog = value; } } public new static void DeleteAll() { ActiveRecordBase < PostEntity > .DeleteAll(); } public new static PostEntity[] FindAll() { return ActiveRecordBase < PostEntity > .FindAll(); } public static PostEntity Find( int id) { return ActiveRecordBase < PostEntity > .Find(id); } public static PostEntity TryFind( int id) { return ActiveRecordBase < PostEntity > .TryFind(id); } }
这种方法会将所有的信息都映射到一个数据表中,通过鉴别器的值DiscriminatorValue来区分各个类的实例(数据表中的一条记录)。
运行下面的代码:
private void TestDiscriminator() { for ( int i = 1 ; i < 6 ; i ++ ) { BlogEntity blog = new BlogEntity( " blog- " + i.ToString()); blog.Create(); } PostEntity post1 = new PostEntity( " post_01 " ); PostEntity post2 = new PostEntity( " post_02 " ); using (TransactionScope tran = new TransactionScope()) { try { BlogEntity blog2 = BlogEntity.Find( 2 ); blog2.Name = " Dotnet Fantasy " ; blog2.Posts.Add(post1); blog2.Posts.Add(post2); blog2.Save(); tran.VoteCommit(); } catch (Exception ex) { MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace); tran.VoteRollBack(); } } }
执行后数据库中EntityBase表的记录:
id type name post_of 1 blog blog-1 NULL 2 blog Dotnet Fantasy NULL3 blog blog-3 NULL 4 blog blog-4 NULL 5 blog blog-5 NULL 6 post post_01 2 7 post post_02 2
结论:
其实,这两种实现方法用“层”的概念来描述更贴切一些。 至于用什么方式来实现所需要的继承,可以按需求来选择(当然不会仅限于这两种方法)。 另外,不知道在NHibernate里处理继承关系是不是会更加灵活呢? 文章来源: