Fork me on GitHub
Castle ActiveRecord学习实践

实现One-Many

  这里我采用上篇中将过(的)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>

  四.编写测试代码

  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关联映射。

实现Many Many

主要内容

  1.准备数据库表

  2.编写实体类

  3.编写测试代码

  一.准备数据库表

  接着在上篇文章中(的)例子,为了实现多对多(的)关系,我们引入Community,即每个Blog可以属于多个社区,每个社区(也)可以有多个Blog。

CREATE TABLE Blogs (
  blog_id   int IDENTITY(1, 1) PRIMARY KEY,
  blog_name  varchar(50),
  blog_author varchar(50)
)
  
CREATE TABLE Blog_Community (
   blog_Id int NOT NULL ,
   community_Id int NOT NULL
)
  
CREATE TABLE Communities (
   community_Id int IDENTITY (1, 1) PRIMARY KEY,
   community_Name varchar (50) ,
   community_Intro varchar (500)
)

  二.编写实体类代码

  为了实现多对多(的)关系,我们要在Blog、Community类中分别使用HasAndBelongsToMany特性,不需要编写Blog_Community类。示例代码:

// Blog
[HasAndBelongsToMany( typeof(Community),
    Table="Blog_Community",
    ColumnRef=" community_id ",
    ColumnKey=" blog_id " )]
public IList Communitys
{
  get { return _community; }
  set { _ community = value; }
}
  
// Community
[HasAndBelongsToMany( typeof(Blog),
    Table="Blog_Community",
    ColumnRef="blog_id",
    ColumnKey="community_id" )]
public IList Blogs
{
  get { return _blog; }
  set { _ blog = value; }
}

  HasAndBelongsToMany(的)参数相信大家都能够看明白,指定关联表名和关联(的)外键(就)可以了。

  注意:这三个参数必须指定,不可以省略!

  HasManyAttribute说明

属性 说明 示例
Cascade 指明哪些操作会从父对象级联到关联(的)对象,相关(的)操作见后面,如果不指定,则为None Cascade=ManyRelationCascadeEnum.All
Inverse 指定(是)否级联操作 Inverse =true|false
Schema 指定Schema(的)名字 Schema="ARDemo"
Table 指定持久化类所关联(的)数据库表名,如果表名与类名相同,可以省略 Table="posts"
ColumnKey 本实体类于另一个实体类关联(的)外键 ColumnKey="community_id"
ColumnRef 另一实体类(的)外键 ColumnRef="blog_id"
Where 指定一个附加SQL(的)Where子句 Where="IsPost = 0"
Lazy 指定(是)否延迟加载关联对象 Lazy=true|false

  Cascade(的)类型值有如下几种

类型 说明
None 不进行级联操作
SaveUpdate 进行级联Save/Update操作
Delete 进行级联Delete操作
All 进行级联Save/Update/Delete操作
AllDeleteOrphan 进行级联Save/Update/Delete操作,并删除无相关父对象(的)子对象

  最后完整(的)实体类如下:

/**//// <summary>
/// Blog (的)摘要说明。
/// </summary>
[ActiveRecord("Blogs")]
public class Blog : ActiveRecordBase
{
  private int _id;
  
  private String _name;
  
  private String _author;
  
  private IList _community;
  
  [PrimaryKey(PrimaryKeyType.Identity, "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; }
  }
  [HasAndBelongsToMany(typeof(Community),
      Table="Blog_Community",
      ColumnRef=" community_id ",
      ColumnKey=" blog_id " )]
  public IList Communities
  {
    get { return _community; }
    set { _community = 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 );
  }
}
  
/**//// <summary>
/// Community (的)摘要说明。
/// </summary>
[ActiveRecord("Communities")]
public class Community : ActiveRecordBase
{
  private int _id;
  
  private String _name;
  
  private String _intro;
  
  private IList _blog;
  
  [PrimaryKey(PrimaryKeyType.Identity, "Community_Id")]
  public int Id
  {
    get { return _id; }
    set { _id = value; }
  }
  
  [Property("Community_Name")]
  public String Name
  {
    get { return _name; }
    set { _name = value; }
  }
  
  [Property("Community_Intro")]
  public String Author
  {
    get { return _intro; }
    set { _intro = value; }
  }
  [HasAndBelongsToMany(typeof(Blog),
      Table="Blog_Community",
      ColumnRef="blog_id",
      ColumnKey="community_id" )]
  public IList Blogs
  {
    get { return _blog; }
    set { _blog = value; }
  }
  
  public static void DeleteAll()
  {
    DeleteAll( typeof(Community) );
  }
  
  public static Community[] FindAll()
  {
    return (Community[]) FindAll( typeof(Community) );
  }
  
  public static Community Find(int id)
  {
    return (Community) FindByPrimaryKey( typeof(Community), id );
  }
}

  三.编写测试代码

  下面(是)我写(的)一些简单(的)测试代码,有兴趣(的)可以看一下。

  1.级联增加:新增一个Blog,让它同时属于好几个社区

[Test]
public void TestCascadingSave()
{
  //新建一个Blog
  Blog blog = new Blog();
  blog.Name = "Tech Space";
  blog.Author = "Terrylee";
  //属于ID为1,2社区
  ArrayList list = new ArrayList();
  list.Add(Community.Find(1));
  list.Add(Community.Find(2));
  blog.Communities = list;
  //保存
  blog.Save();
}

  2.级联更新:对一个已经存在Blog,更改它属于更多(的)社区

[Test]
public void TestCascadingUpdate()
{
  //测试1:查找一个Blog
  Blog blog = Blog.Find(10);
  
  IList clist = blog.Communities;
  
  clist.Add(Community.Find(4));
  clist.Add(Community.Find(3));
  
  blog.Save();
  
  //测试2:查找一个Community
  Community community = Community.Find(3);
  
  IList blist = community.Blogs;
  
  blist.Add(Blog.Find(8));
  
  community.Save();
}

  3.级联删除:删除一个Blog,级联表中对应(的)记录应该删除,但Community不能删除,因为还有别(的)Blog和它关联

[Test]
public void TestCascadingDelete()
{
  //测试1:删除Blog
  Blog blog = Blog.Find(10);
  using(TransactionScope btran = new TransactionScope())
  {
    try
    {
      blog.Delete();
      btran.VoteCommit();
    }
    catch
    {
      btran.VoteRollBack();
    }
  }
  
  //测试2:删除Community
  Community community = Community.Find(3);
  
  using(TransactionScope ctran = new TransactionScope())
  {
    try
    {
      community.Delete();
      ctran.VoteCommit();
    }
    catch
    {
      ctran.VoteRollBack();
    }
  }
}

  好了,关于Many-Many关联映射(就)写这么多了,内容比较简单。下篇文章我会介绍在ActiveRecord中实现延迟加载和使用Where子句。

http://www.qzsou.cn/aWangLuo/aAspNet/47823.html

http://www.qzsou.cn/Search.asp?searchtype=-1&searchword=Castle+ActiveRecord

CastleProject非常庞大,ActiveRecord是其中一个非常适合用于DomainModel开发的O/RMapping框架。它使用.NET的反射特性无需配置文件,集成NHibernate完成数据层持久化功[阅读全文]
主要内容  1.由实体类生成数据表  2.运行存在的SQL脚本  3.使用空属类型  4.使用枚举类型的属性  5.使用NHibernate中的日志记录  一.由实体类生成数据表  在前面所用到的例子中我们都是先有数据表结构,然后才有实体类,然而这会让很多朋友[阅读全文]
主要内容  1.HQL概述  2.SimpleQuery查询  3.ScalarQuery查询  4.自定义查询  5.使用CallBack  一.HQL简单介绍  HQL全名是HibernateQueryLangua[阅读全文]
摘要:写这篇文章缘于昨天跟Linkin的一段聊天。我在使用ActiveRecord的一些技巧一文中的由实体类生成数据库表提到了这样一句话:生成数据库表时只有当该表不存在时ActiveRecord才会生成,否则表如果存在ActiveRecord不会做任何事情,也[阅读全文]
主要内容  1.概述  2.使用Validation  3.如何扩展  4.深入分析验证  一.概述  在录入数据时,对数据有效性的验证是必不可少的,很多时候我们在UI层上就会做一层验证,但有时也需要在底层做一些必要的处理[阅读全文]
摘要:在ActiveRecord中把数据库表之间的关联关系采用对象间的聚合关系来表现,然而这却带来一系列的性能上的问题。就像我在One-Many中用到的例子Blog,使用Blog.Find(1)查找了一个Blog对象,也许[阅读全文]
主要内容  1.准备数据库表  2.编写实体类  3.编写测试代码  一.准备数据库表  接着在上篇文章中的例子,为了实现多对多的关系,我们引入Community,即每个Blog可以属于多个社区,每个社区也可以有多个Blog。CREATETABLEBlog[阅读全文]
主要内容  1.准备数据表结构  2.编写实体类并介绍HasMany和BlongsTo特性  3.构建配置信息  4.编写测试代码  一.准备数据表结构  在这个例子中,我们引入了两个对象Blog、Post,它们之间的关系是一对多,即一个Blog有多篇Post[阅读全文]
主要内容  简单映射  1.ActiveRecordAttribute  2.PrimaryKeyAttribute  3.CompositeKeyAttribute  4.PropertyAttribute  5.FieldAttribute  一.Act[阅读全文]
主要内容  1.需要配置什么  2.如何去配置  3.常见的配置示例  一.需要配置什么  在第一篇大家都已经看到了,其实我们的配置信息跟用NHibernate时的配置是一样的,这是因为ActiveRecord在底层封装了NHibernate。为了没有用过NH[阅读全文]
摘要:最近几天有时间看了一下Castle,原来它的功能是如此的强大,从数据访问框架到IOC容器,再到WEB框架,基本包括了整个开发过程中的所有东西,看来得好好学习研究一下了,并且打算把自己学习过程的一些东西记录下来。先从A[阅读全文]
posted on 2010-12-02 13:48  HackerVirus  阅读(358)  评论(0编辑  收藏  举报