Castle ActiveRecord(四) 映射基础之一

通过前面几篇文章的介绍,相信大家对ActiveRecord已经是管中窥豹。从这篇文章开始,我们将进入比较实质性的内容。在进入实际的映射之前,先让我们系统地介绍一下前面讲过的东西。
这里的内容都参考自Hibernate、NHibernate的文档及ActiveRecord的文档,大家不妨多参考一下,以免这里叙述有误。若发现错误之处,欢迎指正!
1、类(class)
每个类必须继承ActiveRecordBase 且必须使用 ActiveRecord特性.

[ActiveRecord("blogtable")]
public class Blog : ActiveRecordBase
{
}

如果类与之对应的表同名,则表名可以省略:
[ActiveRecord()]
public class Blog : ActiveRecordBase
{
}

更加详细的信息如下表所示:

Access

 

AccessString

 

Cache

 

CustomAccess

 

DiscriminatorColumn

识别器字段名,读写

DiscriminatorType

识别器字段类型,读写

DiscriminatorValue

识别器字段的值,读写

Lazy

是否延时加载,booel类型

Proxy

把一个代理类型同目标类型联系起来,该类型在延时装载的时候将作为代理使用

Schema

schema的名称,可读写

Table

所对应的表名,可读写,如ActiveRecord("Blogs")]

[ActiveRecord(Table="Blogs")]

TypeId (inherited from Attribute)

当在一个派生类中被实现时,为本属性获取一个唯一的标识符

Where

附加的where语句


2、主键(Primary key):
[ActiveRecord()]
public class Blog : ActiveRecordBase
{
  
private int id;
  
  [PrimaryKey]
  
public int Id
  
{
    
get return id; }
    
set { id = value; }
  }

}

这和下面是一样的:
[PrimaryKey(PrimaryKeyType.Native)]
public int Id
{
  
get return id; }
  
set { id = value; }
}

还可以使用序列(sequence)方式的关键字生成(对于内部支持序列的数据库才能使用序列,如DB2,Oracle, PostgreSQL, Interbase, McKoi,SAP DB):
[PrimaryKey(PrimaryKeyType.Sequence, SequenceName="myseqname")]
public int Id
{
  
get return id; }
  
set { id = value; }
}


主键特性的更加详细的信息如下表所示:

Access (inherited from WithAccessAttribute)

 

AccessString (inherited from WithAccessAttribute)

 

Column

 主键字段名称

ColumnType

 主键字段类型

CustomAccess (inherited from WithAccessAttribute)

 

Generator

 是一个.NET类的名字,也就是主键的生成方式,用来为该持久化类的实例生成唯一的标识,使用方法如:PrimaryKeyType.Native,Native就是一个GeneratorGenerator有很多内置实现,见表《主键的生成方式》

Length

 主键字段长度

Params

Params用来提供Generator所需要的配置参数,这些参数用逗号分割

SequenceName

 当主键的生成方式为Sequence时,对应的序列的名称,如:

PrimaryKey(PrimaryKeyType.Sequence, SequenceName="seqname")

TypeId (inherited from Attribute)

When implemented in a derived class, gets a unique identifier for this Attribute.

UnsavedValue

用于标明某个实例时刚刚被实例化的(尚未保存)版本属性值,依靠这个值就可以把这种情况 和已经在先前的session中保存或装载的脱管(detached)实例区分开来。 (undefined指明使用标识属性值进行判断。)

主键的生成方式(Generator的内置实现):

Identity

对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是自增的long, short 或者int类型。

Sequence

在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是自增的long, short或者 int类型。

HiLo

使用一个高/低位算法高效的生成long, short 或者 int类型的标识符。

SeqHiLo

使用一个高/低位算法来高效的生成long, short 或者 int类型的标识符,给定一个数据库序列(sequence)的名字。

UuidHex

产生一个byte[] ,把它转换成字符串作为标识符

UuidString

用System.Guid算法生成字符串类型的标识符

Guid

在MS SQL Server 和 MySQL 中使用数据库生成的GUID字符串

GuidComb

用Jimmy Nilsso的一个算法产生一个新的System.Guid

Native

根据底层数据库的能力选择identity, sequence 或者hilo中的一个。

Assigned

应用程序自己为对象分配一个标示符。

Foreign

使用外部相关联的对象的标识符。

3、联合主键(Composite Keys)
联合主键的使用有点麻烦,首先需要定义一个联合主键类(composite key class),然后在需要使用联合主键的类中添加一个联合主键类(composite key class)类型的属性,并对该属性加以主键特性(PrimaryKey attribute)。如下所示:

//联合主键类
 [CompositeKey, Serializable]
public class MyCompositeKey
{
  
private string _keyA;
  
private string _keyB;

  [KeyProperty]
  
public virtual string KeyA
  
{
    
get return _keyA; }
    
set { _keyA = value; }
  }

  [KeyProperty]
  
public virtual string KeyB
  
{
    
get return _keyB; }
    
set { _keyB = value; }
  }

  
public override string ToString()
  
{
    
return string.Join( ":"new string[] { _keyA, _keyB } );
  }

  
public override bool Equals( object obj )
  
{
    
if( obj == this ) return true;
    
if( obj == null || obj.GetType() != this.GetType() ) return false;
    MyCompositeKey test 
= ( MyCompositeKey ) obj;
    
return ( _keyA == test.KeyA || (_keyA != null && _keyA.Equals( test.KeyA ) ) ) &&
      ( _keyB 
== test.KeyB || ( _keyB != null && _keyB.Equals( test.KeyB ) ) );
  }


  
public override int GetHashCode()
  
{
    
return _keyA.GetHashCode() ^ _keyB.GetHashCode();
  }

}

使用联合主键的类:

[PrimaryKey]
public MyCompositeKey ID
{
  
get return _key; }
  
set { _key = value; }
}

联合主键类(composite key class)必须是可序列化(Serializable)的,并且必须实现Equals和GetHashCode方法顾名思义,。既然是联合主键类,该类至少有两个属性,这些属性都需要使用KeyProperty特性(KeyProperty attribute)。

4、属性(Properties)

下面演示了如何名称与对应的列同名的普通属性:

[Property]
public String Name
{
  
get return name; }
  
set { name = value; }
}

否则你必须指定列名:

[Property("customer_name")]
public String Name
{
  
get return name; }
  
set { name = value; }
}

可以指定更详细的信息:

[Property(Length=10, NotNull=true, Unique=true)]
public String Name
{
  
get return name; }
  
set { name = value; }
}

这些信息主要如下表:

Access (inherited from WithAccessAttribute) 

可选 - 默认值为 property): Hibernate用来访问属性值的策略。

AccessString (inherited from WithAccessAttribute) 

 

Column 

所对应的列(字段)

ColumnType 

列(字段)的类型

CustomAccess (inherited from WithAccessAttribute) 

 

Formula 

(可选): 一个SQL表达式,定义了这个计算 (computed) 属性的值。计算属性没有和它对应的数据库字段

Insert 

(可选 - 默认为 true) : 表明用于UPDATE 和/或 INSERT 的SQL语句中是否包含这个被映射了的字段。

Length 

字段长度

NotNull 

能否为空,Boolean类型

TypeId (inherited from Attribute)

When implemented in a derived class, gets a unique identifier for this Attribute

Unique

是否唯一(唯一性约束),可选,Boolean类型

UnsavedValue

用于标明某个实例时刚刚被实例化的(尚未保存)版本属性值,依靠这个值就可以把这种情况 和已经在先前的session中保存或装载的脱管(detached)实例区分开来。 (undefined指明使用标识属性值进行判断。)

Update 

(可选 - 默认为 true) : 表明用于UPDATE 和/或 INSERT 的SQL语句中是否包含这个被映射了的字段。

5、Fields

使用[Field] 特性可以直接映射field。Field的映射与属性是一样的,如:

[Field]
private String _name;

或:

[Field("customer_name")]
private String _name;

Field的更加详细的信息的指定方法与property相同,这里不再赘述。

当field的数据在一个internal 类(在.NET组件级别,你可以把它视为public,而在外部则为private)中使用的时候,可以使用field映射。通常,properties比field更可取。

6、Nested (嵌套)

可以使用一个集合类(aggregate class)来映射同一个表的数据,例如:

[ActiveRecord]
public class Company : ActiveRecordBase
{
  
private PostalAddress _address;

  [Nested]
  
public PostalAddress Address
  
{
    
get return _address; }
    
set { _address = value; }
  }

}


public class PostalAddress
{
  
private String _address;
  
private String _city;
  
private String _state;
  
private String _zipcode;

  
public PostalAddress()
  
{
  }


  
public PostalAddress(String address, String city,
    String state, String zipcode)
  
{
    _address 
= address;
    _city 
= city;
    _state 
= state;
    _zipcode 
= zipcode;
  }


  [Property]
  
public String Address
  
{
    
get return _address; }
    
set { _address = value; }
  }


  [Property]
  
public String City
  
{
    
get return _city; }
    
set { _city = value;}
  }


  [Property]
  
public String State
  
{
    
get return _state; }
    
set { _state = value; }
  }


  [Property]
  
public String ZipCode
  
{
    
get return _zipcode; }
    
set { _zipcode = value; }
  }

}


NestedAttribute的属性如下表所示:

Update

表明在用于UPDATE 的SQL语句中是否包含这个字段。默认为true

Insert

表明在用于INSERT的SQL语句中是否包含这个字段。默认为true

TypeId

 

7、Version/Timestamp (版本/时间戳)

在ActiveRecord也可以使用Nhibernate的Version和Timestamp。Version表明表中包含附带版本信息的数据,这在你准备使用 长事务(long transactions)的时候特别有用。Timestamp指明了表中包含时间戳数据,用来作为版本的替代。

版本:

[Version("customer_version")]
public Int32 Version
{
  
get return version; }
  
set { version = value; }
}

时间戳:

[Timestamp("customer_timestamp")]
public Int32 Timestamp
{
  
get return ts; }
  
set { ts = value; }
}

版本的属性如下表所示:

Access (inherited from WithAccessAttribute)

NHibernate用于访问属性值的策略

AccessString (inherited from WithAccessAttribute)

 

Column

指定持有版本号的字段名

CustomAccess (inherited from WithAccessAttribute)

 

Type

版本号的类型

TypeId (inherited from Attribute)

 

时间戳的属性如下所示:

Access (inherited from WithAccessAttribute)

NHibernate用于访问属性值的策略

AccessString (inherited from WithAccessAttribute)

 

Column

持有时间戳的字段名

CustomAccess (inherited from WithAccessAttribute)

 

TypeId (inherited from Attribute)

 

一个脱管(detached)实例的version或timestamp不能为空(null),因为NHibernate不管 unsaved-value指定为何种策略,它将分离任何属性为空的version或timestamp 实例为瞬时(transient)实例。 避免NHibernate中的传递重附(transitive reattachment)问题的一个简单方法是 定义一个不能为空的version或timestamp属性,特别是在人们使用程序分配的标识符(assigned identifiers) 或复合主键时非常有用!

posted @ 2006-07-31 17:28  大田  阅读(2435)  评论(2编辑  收藏  举报