http://www.rainsts.net/article.asp?id=484
Castle ActiveRecord 对于数据实体的设计非常灵活,大量特性的使用,使得其代码方式非常类似 WCF 的声明式编程。
1. 实体类型
通常我们会选择从 ActiveRecordBase (或其泛型版本) 继承实体类型,它几乎提供了实体所需的所有操作方法。
[Serializable]
public abstract class ActiveRecordBase<T> : ActiveRecordBase
{
protected internal static int CountAll();
protected internal static void Create(T instance);
protected internal static void Delete(T instance);
public static void DeleteAll();
protected static object Execute(NHibernateDelegate call, object instance);
public static bool Exists();
public static T Find(object id);
public static T[] FindAll();
public static T[] FindAllByProperty(string property, object value);
protected internal static T FindByPrimaryKey(object id);
public static T FindFirst(params ICriterion[] criterias);
public static T FindOne(params ICriterion[] criterias);
protected internal static void Refresh(T instance);
protected internal static void Save(T instance);
public static T[] SlicedFindAll(int firstResult, int maxResults...);
public static T TryFind(object id);
protected internal static void Update(T instance);
...
}
我们看一个简单的例子。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private int id;
[PrimaryKey(Generator=PrimaryKeyType.Identity)]
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique=true, NotNull=true)]
public string Name
{
get { return name; }
set { name = value; }
}
}
public class ARTester
{
public static void Test()
{
ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(),
new XmlConfigurationSource("ar.xml"));
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchema();
User user = new User();
user.Name = "tom";
user.Save();
User user2 = User.Find(user.Id);
Console.WriteLine(user2.Name);
user2.Name = "tomxxx";
user2.Update();
user.Refresh();
Console.WriteLine(user.Name);
}
}
从 ActiveRecordBase 继承并不是强制的,我们可以使用 ActiveRecordMediator 来达到同样的目的。
[ActiveRecord("Users")]
public class User
{
private int id;
[PrimaryKey(Generator=PrimaryKeyType.Identity)]
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique=true, NotNull=true)]
public string Name
{
get { return name; }
set { name = value; }
}
}
public class ARTester
{
public static void Test()
{
ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(),
new XmlConfigurationSource("ar.xml"));
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchema();
User user = new User();
user.Name = "tom";
ActiveRecordMediator<User>.Save(user);
User user2 = ActiveRecordMediator<User>.FindByPrimaryKey(user.Id);
Console.WriteLine(user2.Name);
user2.Name = "tomxxx";
ActiveRecordMediator<User>.Update(user2);
ActiveRecordMediator<User>.Refresh(user);
Console.WriteLine(user.Name);
}
}
除了 ActiveRecordBase,AR 还提供了ActiveRecordValidationBase。它允许我们使用相应的特性对实体成员进行格式验证,其具体使用方法我们会在下一章研究。
2. 映射特性
AR 提供了大量的特性来代替 NHibernate 配置文件,下图是我们常用的实体映射特性。
ActiveRecordAttribute
主要用于指定实体类型和数据表之间的映射关系,我们可以通过构造参数或者 Table 属性设置数据表名称。它还拥有其他大量的属性用来操控实体的缓存策略、继承策略等,具体信息可参考帮助文件。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
}
PrimaryKeyAttribute
用于指定数据表的主键,包括自增字段等。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private int id;
[PrimaryKey(PrimaryKeyType.Identity)]
public int Id
{
get { return id; }
set { id = value; }
}
}
我们也可以直接使用字符串类型的字段作为主键。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private string name;
[PrimaryKey(PrimaryKeyType.Assigned)]
public string Name
{
get { return name; }
set { name = value; }
}
}
不过,这似乎并不是一个好主意,我个人建议还是使用一个标识字段要好一些。当然,我们可以不使用自增类型。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private string id;
[PrimaryKey(PrimaryKeyType.UuidHex)]
public string Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique=true, NotNull=true)]
public string Name
{
get { return name; }
set { name = value; }
}
}
PropertyAttribute / FieldAttribute
这两个特性用来指定实体类型属性、字段与数据表字段的映射关系。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private string id;
[PrimaryKey(PrimaryKeyType.UuidHex)]
public string Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique=true, NotNull=true)]
public string Name
{
get { return name; }
set { name = value; }
}
private int age;
[Property(Column="Age1")]
public int Age
{
get { return age; }
set { age = value; }
}
}
FieldAttribute 的使用方式基本类似。成员属性还包括指定是否不允许为空(NotNull)、约束(Check)、计算公式(Formula)等。最有意思的恐怕就是 Insert & Update 了,它允许我们在执行插入和更新动作时忽略该属性或字段。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private string id;
[PrimaryKey(PrimaryKeyType.UuidHex)]
public string Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique=true, NotNull=true)]
public string Name
{
get { return name; }
set { name = value; }
}
private DateTime createDateTime;
[Property(Update=false)]
public DateTime CreateDateTime
{
get { return createDateTime; }
set { createDateTime = value; }
}
}
public class ARTester
{
public static void Test()
{
ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(),
new XmlConfigurationSource("ar.xml"));
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchema();
User user = new User();
user.Name = "tom";
user.CreateDateTime = DateTime.Now;
user.Save();
Console.WriteLine(user.CreateDateTime);
System.Threading.Thread.Sleep(2000);
User user2 = User.Find(user.Id);
user2.Name = "abc";
user2.CreateDateTime = DateTime.Now.AddDays(100);
user2.Update();
user.Refresh();
Console.WriteLine(user.Name);
Console.WriteLine(user.CreateDateTime);
}
}
输出:
2007-5-8 12:12:46
abc
2007-5-8 12:12:46
这东东还是非常实用的。
CompositeKeyAttribute / KeyPropertyAttribute
用于定义数据表中的组合键。注意,组合键类型必须是可序列化,且重写了 Equals 和 GetHashCode 方法。
[Serializable]
public class Id
{
private int x;
[KeyProperty]
public int X
{
get { return x; }
set { x = value; }
}
private int y;
[KeyProperty]
public int Y
{
get { return y; }
set { y = value; }
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private Id id;
[CompositeKey]
public Id Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique = true, NotNull = true)]
public string Name
{
get { return name; }
set { name = value; }
}
}
public class ARTester
{
public static void Test()
{
ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(),
new XmlConfigurationSource("ar.xml"));
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchema();
User user = new User();
user.Id = new Id();
user.Id.X = 1;
user.Id.Y = 2;
user.Name = "zs";
user.Create(); // 调用 Save() 会出错。????
}
}
NestedAttribute
NestedAttribute 用来标注自定义类型的属性。
public class PostalAddress
{
private string country;
[Property]
public string Country
{
get { return country; }
set { country = value; }
}
private string address;
[Property]
public string Address
{
get { return address; }
set { address = value; }
}
private string postcode;
[Property]
public string Postcode
{
get { return postcode; }
set { postcode = value; }
}
}
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private int id;
[PrimaryKey(PrimaryKeyType.Identity)]
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
[Property(Unique=true, NotNull=true)]
public string Name
{
get { return name; }
set { name = value; }
}
private PostalAddress address;
[Nested]
public PostalAddress Address
{
get { return address; }
set { address = value; }
}
}
public class ARTester
{
public static void Test()
{
ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(),
new XmlConfigurationSource("ar.xml"));
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchema();
User user = new User();
user.Name = "zhagnsan";
user.Address = new PostalAddress();
user.Address.Country = "China";
user.Address.Address = "Beijing...";
user.Address.Postcode = "123456";
user.Save();
User user2 = User.Find(user.Id);
Console.WriteLine(user2.Address.Address);
}
}
------------------------ 注意 --------------------------------
1. 如果某个属性必须是只读的,那么我们就必须指定其 Access。
[ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
private int id;
[PrimaryKey(PrimaryKeyType.Identity, Access=PropertyAccess.FieldCamelcase)]
public int Id
{
get { return id; }
}
}
2. 如果需要使用大尺寸数据,比如长度超过 255 的字符串,或者 byte[],那么我们最好使用 "StringClob" 或者 "BinaryBlob"。
[ActiveRecord]
public class Data : ActiveRecordBase<Data>
{
private int id;
[PrimaryKey(PrimaryKeyType.Identity, Access=PropertyAccess.FieldCamelcase)]
public int Id
{
get { return id; }
}
private string content;
[Property(ColumnType = "StringClob", Length = 2048)]
public string Content
{
get { return content; }
set { content = value; }
}
}
[最后修改由 yuhen, 于 2007-05-08 15:39:03]