摘要:前面几篇文章简单的介绍了ActiveRecord中的基本映射以及构建配置信息,本文我们用ActiveRecord里面的Blog,Post例子来实现One-Many/Many-One关联。

主要内容

1.准备数据表结构

2.编写实体类并介绍HasMany和BlongsTo特性

3.构建配置信息

4.编写测试代码

一.准备数据表结构

在这个例子中,我们引入了两个对象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

)

二.编写实体类

首先我们来看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说明

属性

说明

示例

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的类型值有如下几种

类型

说明

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说明

属性

说明

示例

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类型如下

选项

说明

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) );

    }

}


三.构建配置信息

这里我采用上篇中将过的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关联映射。

参考资料

Castle的官方网站http://www.castleproject.org

转载于:https://www.cnblogs.com/Terrylee/archive/2006/04/06/368471.html

Castle ActiveRecord学习实践(4):实现One-Many关系的映射相关推荐

  1. Castle ActiveRecord学习实践(1):快速入门指南

    摘要:最近几天有时间看了一下Castle,原来它的功能是如此的强大,从数据访问框架到IOC容器,再到WEB框架,基本包括了整个开发过程中的所有东西,看来得好好学习研究一下了,并且打算把自己学习过程的一 ...

  2. Castle ActiveRecord学习实践(2):构建配置信息

    摘要:ActiveRecord在底层封装了NHibernate,在框架启动时需要指定相关的配置信息,那么我们需要配置些什么?又该如何去配置呢?本文将会介绍在ActiveRecord中构建配置信息. 主 ...

  3. Castle ActiveRecord学习实践(8)HQL查询

    本篇来了解下Castle ActiveRecord hql 查询语句. 博客园中讲解Castle ActiveRecord 的文章已经很多了,博主就不自己写了.转载一篇TerryLee大大的文章. 摘 ...

  4. Castle ActiveRecord学习实践(5):实现Many–Many关系的映射

    摘要:多对多的关系在日常开发中也会经常遇到,在ActiveRecord中我们用HasAndBelongsToMany特性来实现Many-Many的关联,本文将通过一个具体的实例来介绍这一用法. 主要内 ...

  5. Castle ActiveRecord学习实践(6):延迟加载和使用Where子句

    摘要:在ActiveRecord中把数据库表之间的关联关系采用对象间的聚合关系来表现,然而这却带来一系列的性能上的问题.就像我在One-Many中用到的例子Blog,使用Blog.Find(1)查找了 ...

  6. Castle ActiveRecord学习实践(7):使用HQL查询

    摘要:虽然ActiveRecord为我们提供了Find()和FindAll()这样两个静态的查询方法,并且有Where特性可供使用,但是仍然不能解决实际开发中一些复杂的查询,这时我们就需要通过HQL查 ...

  7. ActiveRecord学习笔记(四):处理Many-To-Many映射

    本文主要描述了如何使用Castle.ActiveRecord处理Many-To-Many映射.本文主要涉及了两个类:Student(学生).Subject(学科),这两个类的关系是多对多的,因为一个学 ...

  8. Castle ActiveRecord学习笔记四:各种映射

    这里主要来说明ActiveRecord的属性与数据库及其字段的对应关系. 主要以ActiveRecordAttribute.PrimaryKeyAttribute.PropertyAttribute来 ...

  9. Castle ActiveRecord学习(四)延迟加载、分页查询、where条件

    一.延迟加载 //用户发布的主题,一对多:Table:外键表:ColumnKey:外键:Lazy:延迟加载:Cascade:级联操作(级联删除)[HasMany(typeof(ThemeInfo), ...

最新文章

  1. Leetcode 347. Top K Frequent Elements--python1行解法,Java 11ms解法
  2. 苏宁大数据离线任务开发调度平台实践:任务调度模块架构设计
  3. VI编辑器的基本使用
  4. 聊聊AspectCore动态代理中的拦截器(一)
  5. java 按位置格式化字符串_Java字符串格式化,{}占位符根据名字替换实例
  6. 斗鱼递交私有化退市文件 与虎牙合并暂无完成时间表
  7. c语言数据结构的主函数怎么写,您好,关于数据结构C语言的问题,上次百度知道里面主函数没有发上去? 爱问知识人...
  8. inline函数的用法
  9. 深入浅出linux驱动,Linux Kernel 字符驱动的深入浅出讲解
  10. 百度地图和solr展示资源和附近等功能的实现 二
  11. mysql 5.7.16安装与给远程连接权限
  12. Dubbox学习笔记
  13. opencv3.4.x和opencv4.x中 cv2.findContours的不同 ValueError: too many values to unpack (expected 2)
  14. JVM 图形化监控工具
  15. 《VR/AR技术与应用》笔记 001
  16. android 方法映射,高通Android平台驱动层 MSM8916 键值映射方法
  17. oracle怎么确定安装成功,怎么判断oracle是否安装成功
  18. -1-0 Java 简介 java是什么 java简单介绍
  19. GPL协议允许你怎么卖?
  20. 数据库到底是什么?举例MySQL给你讲明白

热门文章

  1. 浙江大学计算机视频 百度云,浙江大学 数据结构与算法 全40讲 徐镜春 视频教程...
  2. Linux下给arm的引脚电平,ARM-Linux GPIO操作事宜
  3. Android分级部门选择界面(二)
  4. 量子计算的基本原理——本质上是在操作薛定谔的猫(同时去运算和操作死+不死两种状态)...
  5. 【C语言应用实例】输出当月日历
  6. 【TP5笔记】TinkPHP5中引入资源文件
  7. app让个别界面横屏,其他的为竖屏,解决如下
  8. div+css中设置了float属性后如何让外层的高度随着内层的高度大小自动调整
  9. [POJ1330 Nearest Common Ancestors]
  10. JS DOM 操作实现代码