在面向对象的设计中继承是少不了的,那么如何在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=SomeName
xx.CompanyEntity, ID=100, CompId=0, Name=SomeName
xx.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 NULL
3 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里处理继承关系是不是会更加灵活呢?
文章来源:http://www.agilelabs.cn/blogs/%e8%8c%83%e4%bf%8a/archive/2006/05/16/1216.aspx
转载于:https://www.cnblogs.com/debug1/archive/2006/05/16/413757.html