注:本文翻译自Castle的官方网站http://www.castleproject.org
有关Castle的更多内容请参阅李会军博客的系列文章
http://terrylee.cnblogs.com/archive/2006/04/28/castl_ioc_article.html
本文所用代码下载页面:
http://www.castleproject.org/activerecord/gettingstarted/index.html
配置要求
我们假定你安装了Castle Project assemblies以及自带的NHibernate assemblies,如果没有的话你可以下载安装MSI installer distribution(http://www.castleproject.org/castle/download.html)
本文假定你使用的是MSSQL Server 2003,不过NHibernate也支持其它的数据库.
如果你使用的是Visual Studio .Net,记得添加这些引用:
.Castle.ActiveRecord.dll
.Castle.Core.dll
.Castle.DynamicProxy.dll
.Iesi.Collections.dll
.log4net.dll
.NHibernate.dll
如果你使用的是其它的环境,务必在Castle安装目录里引用上述assemblies
创建数据库及表
我们将在数据库test里创建3个表:User, Blog 和 Post.你可以按如下构架创建或让ActiveRecord生成该构架.
如你所见,User是孤立的表,而Blog 和 Post表是相互关联的,一个博客可以有很多文章,所以对blog来说是一对多关系,而对post来说是多对一关系.
图2
创建类
现在我们要创建表的对应的类,你将看到这是多么的容易.首先我们创建最简单的User class:
创建User class
1.创建名为User的空类,添加using声明:
namespace BlogSample
{
using System;
using Castle.ActiveRecord;
public class User
{
}
}
2.标明该类源自ActiveRecordBase,使用ActiveRecord特性:
namespace BlogSample
{
using System;
using Castle.ActiveRecord;
[ActiveRecord]
public class User : ActiveRecordBase
{
}
}
3.添加相应的域(field)和属性:
namespace BlogSample
{
using System;
using Castle.ActiveRecord;
[ActiveRecord]
public class User : ActiveRecordBase
{
private int id;
private string username;
private string password;
public int Id
{
get { return id; }
set { id = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
}
}
4.最后,添加特性以告知ActiveRecord这些属性的类别(也就是propertie, primary key 和 relationship).在此,我们将Id标记为primary key而余下的标记为property:
namespace BlogSample
{
using System;
using Castle.ActiveRecord;
[ActiveRecord]
public class User : ActiveRecordBase
{
private int id;
private string username;
private string password;
[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Property]
public string Username
{
get { return username; }
set { username = value; }
}
[Property]
public string Password
{
get { return password; }
set { password = value; }
}
}
}
这就完了,现在我们要创建Blog类和Post类,过程很简单,你自己试试吧.
创建Blog class
该Blog类简单易懂,不过还没有完,我们将创建一个连接Blog和Post的纽带,稍后你将看到.
namespace BlogSample
{
using System;
using System.Collections;
using Castle.ActiveRecord;
[ActiveRecord]
public class Blog : ActiveRecordBase
{
private int id;
private String name;
private String author;
public Blog()
{
}
[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Property]
public String Name
{
get { return name; }
set { name = value; }
}
[Property]
public String Author
{
get { return author; }
set { author = value; }
}
}
}
创建Post class
该Post类也很简单,我们也需要将其与Blog类联系起来.些许不同在于,Contents属性使用[Property(ColumnType="StringClob")],这是必须的,因为该属性绑定到text字段.
namespace BlogSample
{
using System;
using Castle.ActiveRecord;
[ActiveRecord]
public class Post : ActiveRecordBase
{
private int id;
private String title;
private String contents;
private String category;
private DateTime created;
private bool published;
public Post()
{
created = DateTime.Now;
}
[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Property]
public String Title
{
get { return title; }
set { title = value; }
}
[Property(ColumnType="StringClob")]
public String Contents
{
get { return contents; }
set { contents = value; }
}
[Property]
public String Category
{
get { return category; }
set { category = value; }
}
[Property]
public DateTime Created
{
get { return created; }
set { created = value; }
}
}
}
即使你第一次使用你也要承认用起来很简单,添加relationship也不难.
添加relationships
现在要告知ActiveRecord,类Blog 和 Post和有关联,对一对多关系要使用HasManyAttribute,而多对一关系要用BelongsToAttribute
对Post class使用BelongsTo
1.我们要在Post class里添加一个field 和 property以使Blog实例包含Post
[ActiveRecord]
public class Post : ActiveRecordBase
{
...
private Blog blog;
...
public Blog Blog
{
get { return blog; }
set { blog = value; }
}
2.最后对属性添加BelongsToAttribute,以告知ActiveRecord这是一个多对一关系.注意,默认时字段名和属性名是一样的.此时字段名为BlogId,我们的属性名用的是Blog.
对Blog class使用HasMany
1.同样的,我们要向Blog class添加一个field 和 property,以包含所有的Post实例.
using System;
using System.Collections;
using Castle.ActiveRecord;
[ActiveRecord]
public class Blog : ActiveRecordBase
{
...
private IList posts = new ArrayList();
...
public IList Posts
{
get { return posts; }
set { posts = value; }
}
2.向属性添加HasManyAttribute,以告知ActiveRecord这是一个一对多关系:
[HasMany(typeof(Post))]
public IList Posts
{
get { return posts; }
set { posts = value; }
}
HasManyAttribute有一些有用的特性用来更好的控制relationship行为。比如当2个类有关联时,它们之间就有一种"双边关系"(bidirectional relationship),那么由哪边来主导这种关系呢?你可能会想到将post添加到blog.Posts collection 集或使用Post.Blog属性。我要说的是就本例而言,使用Post.Blog是比较妥当的.为此,我们用Inverse属性:
[HasMany(typeof(Post), Inverse=true)]
public IList Posts
{
get { return posts; }
set { posts = value; }
}
我们也要定义其cascade行为.比如当用户删除blog时,NHibernate如何处理那些所属的post?我们的答案是全部删除:
[HasMany(typeof(Post), Inverse=true, Cascade=ManyRelationCascadeEnum.AllDeleteOrphan)]
public IList Posts
{
get { return posts; }
set { posts = value; }
}
另一件事你应该知道:Castle ActiveRecord会推断有外联关系的表和字段,这是因为另一边(比如Post class)有一个BelongsTo特性指向Blog.如果没有,你可以包含这些表和字段信息,比如下面:
[HasMany(typeof(Post),
Table="Posts", ColumnKey="blogid",
Inverse=true, Cascade=ManyRelationCascadeEnum.AllDeleteOrphan)]
public IList Posts
{
get { return posts; }
set { posts = value; }
}
接下来我们要启动framework并处理上述代码了
初始化framework
在调用任何类之前,Castle ActiveRecord必须要初始化.该过程只能执行一次且最好在程序启动时进行.就本例而言,由于我们的示例为WinForms 应用程序.我们必须要初始化ActiveRecord.
ActiveRecord也需要些许配置来告知使用哪个数据库。实际上当初始化NHibernate时,ActiveRecord也继承(pass on)了NHibernate配置.现在我们要决定如何存储配置信息.
配置ActiveRecord
当配置ActiveRecord以及如何保存储配置信息时,我们有多种选择.在官方文档里对对此做了详细阐述.为简单起见,我们使用一个简单的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>
注意:上述配置使用的是SQL Server 2000数据库.如果你使用的是其它数据库,你需要做相应的改动.具体信息请参阅Xml Configuration Reference(Xml Configuration Reference).
现在将上述内容保存为appconfig.xml(并存储在生成assembly的文件夹里),如下的代码创建了一个
XmlConfigurationSource以加载上述配置信息.
namespace BlogSample
{
using System.Windows.Forms;
using BlogSample.UI;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework.Config;
public class App
{
public static void Main()
{
XmlConfigurationSource source = new XmlConfigurationSource("appconfig.xml");
}
}
}
初始化ActiveRecord
最后我们要通过加载配置信息来初始化ActiveRecord.我们也需要指定ActiveRecord的类型.我们可以指定一个assemblies、一个assemblies数组或一个type数组.为简单起见,我们用一个type数组:
namespace BlogSample
{
using System.Windows.Forms;
using BlogSample.UI;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework.Config;
public class App
{
public static void Main()
{
XmlConfigurationSource source = new XmlConfigurationSource("appconfig.xml");
ActiveRecordStarter.Initialize( source, typeof(Blog), typeof(Post), typeof(User) );
}
}
}
此时我们就可以使用了(只要配置正确,数据库存在)
创建表
如果你还没有创建表的话,可以让ActiveRecord来为我们创建:
public class App
{
public static void Main()
{
XmlConfigurationSource source = new XmlConfigurationSource("appconfig.xml");
ActiveRecordStarter.Initialize( source, typeof(Blog), typeof(Post), typeof(User) );
if (MessageBox.Show("Do you want to let ActiveRecord create the database tables?",
"Schema", MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
DialogResult.Yes)
{
ActiveRecordStarter.CreateSchema();
}
}
}
我们将在类里包含一些方法来执行更多的数据库相关操作.
使用类
如果你现在对ActiveRecord比较了解了的话,我们只需要使用我们创建好了的类.
创建第一个用户
我们的应用程序有一个登录窗口,你必须提供正确的用户名和密码才能运行余下的程序.但是数据库才刚刚创建,我们如何添加第一个用户呢?如下的代码创建了一个用户,它应该添加到main class,如下:
User user = new User("admin", "123");
user.Create();
但如果我们多次运行程序呢?一个比较好的解决办法是,只有在数据库里user为空才创建用户,我们可以统计现有的user,若为0,则创建用户"admin":
if (User.GetUsersCount() == 0)
{
User user = new User("admin", "123");
user.Create();
}
很明显,我们要向User class添加方法GetUsersCount:
[ActiveRecord("[User]")]
public class User : ActiveRecordBase
{
...
public static int GetUsersCount()
{
return CountAll(typeof(User));
}
}
login窗体
供登录的窗口如下:
图3
代码很简单,利用一个查找方法来看用户是否存在:
private void logInButton_Click(object sender, System.EventArgs e)
{
User user = User.FindByUserName(loginText.Text);
if (user == null)
{
MessageBox.Show(this, "User not found", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
if (user.Password != passwordText.Text)
{
MessageBox.Show(this, "Wrong password", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
DialogResult = DialogResult.OK;
Hide();
}
为此,我们要包含一个FindByUserName方法:
using NHibernate.Expression;
[ActiveRecord("[User]")]
public class User : ActiveRecordBase
{
...
public static User FindByUserName(string userName)
{
// Note that we use the property name, _not_ the column name
return (User) FindOne(typeof(User), Expression.Eq("Username", userName));
}
}
blog管理
该窗口允许添加、编辑、删除一个blog,同时还有一个窗口对选定blog所属的post进行管理.
当你单击Add或选中一个现有的blog,将显示另一个窗体.
图5
要填充blog列表,我们要选择所有的现有blog:
private void PopulateBlogList()
{
blogsList.Items.Clear();
foreach(Blog blog in Blog.FindAll())
{
ListViewItem item = blogsList.Items.Add(blog.Id.ToString());
item.Tag = blog;
item.SubItems.Add(blog.Name);
item.SubItems.Add(blog.Author);
}
}
为此我们要在Blog class里添加FindAll方法,此外我们还有添加一个方法获取主键值primary key:
[ActiveRecord]
public class Blog : ActiveRecordBase
{
...
public static Blog[] FindAll()
{
return (Blog[]) ActiveRecordBase.FindAll(typeof(Blog));
}
public static Blog Find(int id)
{
return (Blog) ActiveRecordBase.FindByPrimaryKey(typeof(Blog), id);
}
...
要向数据库添加一个新的blog,为此添加如下代码:
Blog blog = new Blog();
blog.Name = "My blog";
blog.Author = "hammett";
blog.Create();
假如你只记得blog的id值,我们可以:
Blog blog = Blog.Find(100); // Id that we know exists
blog.Name = "Different name";
blog.Author = "Different author";
blog.Update();
要删除一个blog实例,仅仅需要调用Delete方法即可.
posts管理
对post来说,我们需要将blog实例与创建的post关联起来:
currentPost.Blog = parentBlog;
currentPost.Title = titleText.Text;
currentPost.Contents = contentsText.Text;
currentPost.Category = categoryText.Text;
currentPost.Created = createdDtTime.Value;
currentPost.Published = publishedCheck.Checked;
currentPost.Save();
更多功能请参阅官方文档!