[Castle ActiveRecord] 2. ActiveRecord

本文介绍了 Castle ActiveRecord 的核心功能,包括实体类型设计、常用映射特性等,并通过实例展示了如何使用 ActiveRecordBase 和 ActiveRecordMediator 进行实体操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值