您的位置:首页 > 编程语言 > C#

C#.Net Castle ActiveRecord学习实践(4):实现One-Many关系的映射

2008-11-13 17:49 736 查看
摘要:前面几篇文章简单的介绍了ActiveRecord中的基本映射以及构建配置信息,本文我们用ActiveRecord里面的Blog,Post例子来实现One-Many/Many-One关联。
主要内容[/b]
1.准备数据表结构
2.编写实体类并介绍HasMany和BlongsTo特性
3.构建配置信息
4.编写测试代码

一.准备数据表结构[/b]
在这个例子中,我们引入了两个对象Blog、Post,它们之间的关系是一对多,即一个Blog有多篇Post。需要用到的数据表结构如下


CREATE TABLE Blogs (




blog_id int IDENTITY(1, 1) PRIMARY KEY,




blog_name varchar(50),




blog_author varchar(50)




)









CREATE TABLE Posts (




post_id int IDENTITY(1, 1) PRIMARY KEY,




post_title varchar(50),




post_contents text,




post_categories varchar(50),




post_blogid int FOREIGN KEY REFERENCES Blogs (blog_id),




post_created datetime,




post_published bit




)

二.编写实体类[/b]

首先我们来看Blog实体类的编写,需要用到HasMany特性,这时我们会在Blog实体类中定义一个Posts属性,用它来表示该Blog所发表的所有Posts,代码如下




[ActiveRecord("Blogs")]




public class Blog : ActiveRecordBase








{




//……




private IList _posts;









[HasMany(typeof(Post), Table="posts", ColumnKey="post_blogid")]




public IList Posts








{






get

{ return _posts; }






set

{ _posts = value; }




}




}

HasManyAttribute说明

属性[/b]
说明[/b]
示例[/b]
Cascade
指明哪些操作会从父对象级联到关联的对象,相关的操作见后面,如果不指定,则为None
Cascade=ManyRelationCascadeEnum.All
Inverse
指定是否级联操作
Inverse =true|false
Schema
指定Schema的名字
Schema="ARDemo"
Table
指定持久化类所关联的数据库表名,如果表名与类名相同,可以省略
Table="posts"
ColumnKey
指定关联类的一个属性,这个属性将会和本外键相对应。
ColumnKey="post_blogid"
Where
指定一个附加SQL的Where子句
Where="IsPost = 0"
Lazy
指定是否延迟加载关联对象
Lazy=true|false
Cascade的类型值有如下几种

类型[/b]
说明[/b]
None
不进行级联操作
SaveUpdate
进行级联Save/Update操作
Delete
进行级联Delete操作
All
进行级联Save/Update/Delete操作
AllDeleteOrphan
进行级联Save/Update/Delete操作,并删除无相关父对象的子对象
在Post实体类中,我们需要定义一个Blog类型的属性,并且用到BlongsTo特性,即一个Post属于某一个Blog,代码如下:


[ActiveRecord("Posts")]




public class Post : ActiveRecordBase








{




//……




private Blog _blog;









[BelongsTo("blogid")]




public Blog Blog








{






get

{ return _blog; }






set

{ _blog = value; }




}




}

BelongsToAttribute说明

属性[/b]
说明[/b]
示例[/b]
Cascade
指定级联操作
Cascade=CascadeEnum.SaveUpdate
Column
列名,外键字段名
BelongsTo("blogid")
Column="blogid"
Insert
是否允许增加
Insert=true|false
NotNull
是否允许为空
NotNull =true|false
OuterJoin
是否允许外连接抓取
OuterJoin=OuterJoinEnum.True
Unique
是否唯一
Unique =true|false
Update
是否允许更新
Update =true|false
Cascade类型如下

选项[/b]
说明[/b]
None
默认值,不进行级联操作
All
进行级联Save/Update/Delete操作
SaveUpdate
进行级联Save/Update操作
Delete
进行级联Delete操作
OuterJoin选项有三个:Auto,True,False
最后完整的Blog实体类如下




/**//// <summary>




/// Blog 的摘要说明。




/// </summary>




[ActiveRecord("Blogs")]




public class Blog : ActiveRecordBase








{




private int _id;









private String _name;









private String _author;









private IList _posts;









[PrimaryKey(PrimaryKeyType.Native, "blog_id")]




public int Id








{






get

{ return _id; }






set

{ _id = value; }




}









[Property("blog_name")]




public String Name








{






get

{ return _name; }






set

{ _name = value; }




}









[Property("blog_author")]




public String Author








{






get

{ return _author; }






set

{ _author = value; }




}









[HasMany(typeof(Post), Table="posts", ColumnKey="post_blogid")]




public IList Posts








{






get

{ return _posts; }






set

{ _posts = value; }




}









public static void DeleteAll()








{




DeleteAll( typeof(Blog) );




}









public static Blog[] FindAll()








{




return (Blog[]) FindAll( typeof(Blog) );




}









public static Blog Find(int id)








{




return (Blog) FindByPrimaryKey( typeof(Blog), id );




}




}

完整的Post类如下






/**//// <summary>




/// Post 的摘要说明。




/// </summary>




[ActiveRecord("Posts")]




public class Post : ActiveRecordBase








{




private int _id;









private String _title;









private String _contents;









private String _category;









private DateTime _created;









private bool _published;









private Blog _blog;









public Post()








{




_created = DateTime.Now;




}









public Post(Blog blog, String title, String contents, String category) : this()








{




_blog = blog;




_title = title;




_contents = contents;




_category = category;




}









[PrimaryKey(PrimaryKeyType.Native,"post_id")]




public int Id








{






get

{ return _id; }






set

{ _id = value; }




}









[Property("post_title")]




public String Title








{






get

{ return _title; }






set

{ _title = value; }




}









[Property(Column="post_contents",ColumnType="StringClob")]




public String Contents








{






get

{ return _contents; }






set

{ _contents = value; }




}









[Property("post_categories")]




public String Category








{






get

{ return _category; }






set

{ _category = value; }




}









[BelongsTo("post_blogid")]




public Blog Blog








{






get

{ return _blog; }






set

{ _blog = value; }




}









[Property("post_created")]




public DateTime Created








{






get

{ return _created; }






set

{ _created = value; }




}









[Property("post_published")]




public bool Published








{






get

{ return _published; }






set

{ _published = value; }




}









public static void DeleteAll()








{




ActiveRecordBase.DeleteAll( typeof(Post) );




}









public static Post[] FindAll()








{




return (Post[]) ActiveRecordBase.FindAll( typeof(Post) );




}




}

三.构建配置信息[/b]
这里我采用上篇中将过的XML配置方式


<?xml version="1.0" encoding="utf-8" ?>




<activerecord>




<config>




<add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />




<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />




<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />




<add key="hibernate.connection.connection_string" value="Data Source=.;Initial Catalog=test;Integrated Security=SSPI" />




</config>




</activerecord>

四.编写测试代码[/b]
1.级联增加:新增一个Blog,并同时添加相关的Post到数据表中


[Test]




public void TestCascadingSave()








{




//创建Blog对象




Blog blog = new Blog();




blog.Name="Terrylee's Tech Space";




blog.Author = "Terrylee";









//执行事务,持久化对象到数据库




using(TransactionScope tran = new TransactionScope())








{




try








{




blog.Create();









for(int i=1;i<11;i++)








{




//创建Post对象




Post post = new Post();




post.Title="This is my "+i.ToString()+" post";




post.Category="Castle";




post.Blog = blog;




post.Save();




}









tran.VoteCommit();




}




catch








{




tran.VoteRollBack();




}




}// The changes will be sent to the DB when the session is disposed here




}

2.级联更新:
首先我们为一个已经存在的Blog增加多个Post



[Test]




public void TestCascadingUpdate()








{




//找到ID为5的Blog




Blog blog = Blog.Find(5);









//执行事务,持久化对象到数据库




using(TransactionScope tran = new TransactionScope())








{




try








{




for(int i=1;i<5;i++)








{




//创建Post对象




Post post = new Post();




post.Title="This is my "+i.ToString()+" post";




post.Category="Castle";









post.Save();









//注意这句




blog.Posts.Add(post);




}









blog.Update();









tran.VoteCommit();




}




catch








{




tran.VoteRollBack();




}




}




}

当然上面的更新代码也可以这样去写:


[Test]




public void TestCascadingUpdate()








{




//找到ID为5的Blog




Blog blog = Blog.Find(5);









//执行事务,持久化对象到数据库




using(TransactionScope tran = new TransactionScope())








{




try








{




for(int i=1;i<5;i++)








{




//创建Post对象




Post post = new Post();




post.Title="This is my "+i.ToString()+" post";




post.Category="Castle";









//在这儿指定它们的关联




post.Blog = blog;




post.Save();




}









tran.VoteCommit();




}




catch








{




tran.VoteRollBack();




}




}




}

但是如果我们去掉post.Save()这句话,就会发现Post并没有增加到库中:


[Test]




public void TestCascadingUpdate()








{




//找到ID为5的Blog




Blog blog = Blog.Find(5);









//执行事务,持久化对象到数据库




using(TransactionScope tran = new TransactionScope())








{




try








{




for(int i=1;i<5;i++)








{




//创建Post对象




Post post = new Post();




post.Title="This is my "+i.ToString()+" post";




post.Category="Castle";









//注释掉这句




//post.Save();









blog.Posts.Add(post);




}









blog.Update();









tran.VoteCommit();




}




catch








{




tran.VoteRollBack();




}




}




}

此时,必须修改我们的Blog类,设置级联操作为SaveUpdate,上面的代码才可以正常执行


//







[HasMany(typeof(Post), Table="posts", ColumnKey="post_blogid",Cascade=ManyRelationCascadeEnum.SaveUpdate)]




public IList Posts








{






get

{ return _posts; }






set

{ _posts = value; }




}

下面再测试一个删除某一个Blog的某些Post后,再保存


[Test]




public void TestCascadingUpdateDel()








{




//找到ID为7的Blog




Blog blog = Blog.Find(7);




int expectedCount = blog.Posts.Count;









using(TransactionScope tran = new TransactionScope())








{




try








{




blog.Posts.RemoveAt(0);









blog.Update();









tran.VoteCommit();




}




catch








{




tran.VoteRollBack();




}




}









int actualCount = Blog.Find(7).Posts.Count;









Assert.AreEqual(expectedCount-1,actualCount);




}

上面这段代码测试可以通过,但是我们会发现表Posts中会有一些记录没有BlogId,修改Blog实体类重新设置级联操作,就可以正常删除了:


//







[HasMany(typeof(Post), Table="posts", ColumnKey="post_blogid",Cascade=ManyRelationCascadeEnum.AllDeleteOrphan)]




public IList Posts








{






get

{ return _posts; }






set

{ _posts = value; }




}

3.级联删除
删除一个Blog对象后,对应的Post对象应该全部删除


[Test]




public void TestCascadingDelete()








{




//找到ID为7的Blog对象




Blog blog = Blog.Find(5);









using(TransactionScope tran = new TransactionScope())








{




try








{




blog.Delete();









tran.VoteCommit();




}




catch








{




tran.VoteRollBack();




}




}




}

同样要注意设置级联操作。
关于One-Many关联映射就介绍这么多了,至于Many-One关联同One-Many,只不过对HasMany和BlongsTo设置的位置不一样而已,在下一篇文章中我会介绍在ActiveRecord中实现Many-Many关联映射。

参考资料[/b]
Castle的官方网站http://www.castleproject.org作者:TerryLee

出处:http://terrylee.cnblogs.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: