Castle学习之二:处理主键时PrimaryKeyType.Assigned等几个有用的属性

ActiveRecord里主键是不应该被赋值的,调用ActiveRecordBase.Create()时,会自动生成一个新的主键.

如果有以下的代码:
 1      [ActiveRecord( " book_School " )]
 2       public   class  School : ActiveRecordBase < School >
 3      {
 4          Guid _id;
 5           string  _name;
 6 
 7          [PrimaryKey(PrimaryKeyType.GuidComb]
 8           public  Guid Id
 9          {
10               get  {  return  _id; }
11               set  { _id  =  value; }
12          }
13 
14          [Property(NotNull = true )]
15           public   string  Name
16          {
17               get  {  return  _name; }
18               set  { _name  =  value; }
19          }
20      }

我们在使用时,由于Id是可赋值的,很容易犯错,有没有办法让编译器保证我们没有对Id进行赋值呢?

答案是有:直接把属性Id的setter去掉就行了.

但是这样一来,ActiveRecord框架本身想要设置这个属性时就有麻烦了,它找不到setter,所以我们必须告诉它怎么设置这个属性的值:把PrimaryKeyAttribute的Access设置成PropertyAccess.FieldCamelcaseUnderscore(意思是给这个属性赋值时,如果找不到setter,就直接向名称符合以下规则的字段赋值,这个规则就是:把属性的名字转换成 camelCase,然后再前面加一个下划线).这样一来,ActiveRecord向Id设置值时,发现这个属性没有setter,于是向名为_id的字段赋值.
 1      [ActiveRecord( " book_School " )]
 2       public   class  School : ActiveRecordBase < School >
 3      {
 4          Guid _id;
 5           string  _name;
 6 
 7          [PrimaryKey(PrimaryKeyType.GuidComb, Access  =  PropertyAccess.FieldCamelcaseUnderscore)]
 8           public  Guid Id
 9          {
10               get  {  return  _id; }
11          }
12 
13          [Property(NotNull = true )]
14           public   string  Name
15          {
16               get  {  return  _name; }
17               set  { _name  =  value; }
18          }
19      }

考虑到大家的个人习惯不同,ActiveRecord还提供了FieldCamelcase (例:userId), FieldLowercaseUnderscore (例:_userid), FieldPascalcaseMUnderscore(例:m_UserId).

如果一定要手工设置主键的值,需要使用到PrimaryKeyType.Assigned.据 NHibernate的文档所述:

[quote]

If you want the application to assign identifiers (as opposed to having NHibernate generate them), you may use the assigned generator. This special generator will use the identifier value already assigned to the object's identifier property. Be very careful when using this feature to assign keys with business meaning (almost always a terrible design decision).

Due to its inherent nature, entities that use this generator cannot be saved via the ISession's SaveOrUpdate() method. Instead you have to explicitly specify to NHibernate if the object should be saved or updated by calling either the Save() or Update() method of the ISession.

[/quote]

下面是综合运用以上所说的属性的代码:

ContractedBlock.gif ExpandedBlockStart.gif School.cs
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using Castle.ActiveRecord;
 5 
 6 namespace BookStore.Components
 7 {
 8     [ActiveRecord("book_School")]
 9     public class School : ActiveRecordBase<School>
10     {
11         Guid _id;
12         string _name;
13 
14         IList<TClass> _classes = new List<TClass>();
15 
16         [PrimaryKey(PrimaryKeyType.Guid, Access = PropertyAccess.FieldCamelcaseUnderscore)]
17         public Guid Id
18         {
19             get { return _id; }
20         }
21 
22         [Property(NotNull=true)]
23         public string Name
24         {
25             get { return _name; }
26             set { _name = value; }
27         }
28 
29         [HasMany(typeof(TClass), Inverse = true, Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Access = PropertyAccess.FieldCamelcaseUnderscore)]
30         public IList<TClass> Classes
31         {
32             get { return _classes; }
33         }
34 
35     }
36 }
37 

ContractedBlock.gif ExpandedBlockStart.gif TClass.cs
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using Castle.ActiveRecord;
 5 
 6 namespace BookStore.Components
 7 {
 8     [ActiveRecord("book_class")]
 9     public class TClass : ActiveRecordBase<TClass>
10     {
11         Guid _id;
12         string _name;
13         int _birthYear;
14 
15         IList<UserInfo> _users=new List<UserInfo>();
16         School _school;
17 
18         [PrimaryKey(PrimaryKeyType.Guid, Access = PropertyAccess.FieldCamelcaseUnderscore)]
19         public Guid Id
20         {
21             get { return _id; }
22         }
23 
24         [Property(NotNull=true)]
25         public int BirthYear
26         {
27             get { return _birthYear; }
28             set { _birthYear = value; }
29         }
30 
31         [Property(NotNull=true)]
32         public string Name
33         {
34             get { return _name; }
35             set { _name = value; }
36         }
37 
38         [BelongsTo("schoolId", NotNull=true)]
39         public School School
40         {
41             get { return _school; }
42             set { _school = value; }
43         }
44 
45         [HasMany(typeof(UserInfo), Inverse = true, Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Access = PropertyAccess.FieldCamelcaseUnderscore)]
46         public IList<UserInfo> Users
47         {
48             get { return _users; }
49         }
50     }
51 }
52 

这里,为了与asp.net MemberShip Provider对接, UserInfo.Id不可能由ActiveRecord自动生成,必须使用属性PrimaryKeyType.Assigned:
ContractedBlock.gif ExpandedBlockStart.gif UserInfo.cs
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using Castle.ActiveRecord;
 5 
 6 namespace BookStore.Components
 7 {
 8     [ActiveRecord("book_user")]
 9     public class UserInfo : ActiveRecordBase<UserInfo>
10     {
11         Guid _id;
12         TClass _class;
13 
14         [PrimaryKey(PrimaryKeyType.Assigned)]
15         public Guid Id
16         {
17             get { return _id; }
18             set { _id = value; }
19         }
20 
21         [BelongsTo("classId", NotNull=true)]
22         public TClass Class
23         {
24             get { return _class; }
25             set { _class = value; }
26         }
27 
28         public static UserInfo Find(Guid id)
29         {
30             UserInfo[] results= FindAllByProperty("Id", id);
31             if (results.Length == 1)
32                 return results[0];
33             throw new NHibernate.HibernateException(string.Format("User with id={0} is in more than 1 classes.",id));
34         }
35 
36         public static new UserInfo Find(object id)
37         {
38             Nullable<Guid> theId = id as Nullable<Guid>;
39             if (id != null)
40                 return Find(theId.Value);
41             throw new NHibernate.HibernateException(string.Format("UserId(0) should be GUID.",id));
42         }
43     }
44 }
45 

ContractedBlock.gif ExpandedBlockStart.gif Tests.cs
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using NUnit.Framework;
 5 using Castle.ActiveRecord;
 6 using Castle.ActiveRecord.Framework.Config;
 7 using BookStore.Components;
 8 
 9 namespace BookStore.Tests
10 {
11     [TestFixture]
12     public class BookStoreTest
13     {
14         [TestFixtureSetUp]
15         public void SetUpAll()
16         {
17             XmlConfigurationSource source = new XmlConfigurationSource("appconfig.xml");
18 
19             ActiveRecordStarter.Initialize(source, typeof(School), typeof(TClass), typeof(UserInfo));
20 
21             ActiveRecordStarter.CreateSchema();
22             school = new School();
23             school.Name = schoolName;
24             school.Create();
25 
26             theClass = new TClass();
27             theClass.Name = className;
28             theClass.School = school;
29             theClass.BirthYear = 2000;
30             theClass.Create();
31         }
32 
33         School school;
34         string schoolName = "中国矿业大学(北京)";
35         string className = "市场管理001班";
36         TClass theClass;
37 
38         [Test]
39         public void Schools()
40         {
41             Assert.AreEqual(1, School.FindAll().Length);
42             School newSchool = School.Find(school.Id);
43             Assert.AreEqual(school.Id, newSchool.Id);
44             Assert.AreEqual(schoolName, newSchool.Name);
45         }
46 
47         [Test]
48         public void Classses()
49         {
50             Assert.AreEqual(1, TClass.FindAll().Length);
51             TClass newClass = TClass.Find(theClass.Id);
52             Assert.AreEqual(theClass.Id, newClass.Id);
53             Assert.AreEqual(className, newClass.Name);
54             Assert.AreEqual(schoolName, newClass.School.Name);
55             Assert.AreEqual(2000, newClass.BirthYear);
56         }
57 
58         [Test]
59         public void UserInfos()
60         {
61             UserInfo user = new UserInfo();
62             user.Id = Guid.NewGuid();
63             user.Class = theClass;
64             user.Create();
65 
66             Assert.AreEqual(1, UserInfo.FindAll().Length);
67             UserInfo newUser = UserInfo.Find(user.Id);
68             Assert.AreEqual(user.Id, newUser.Id);
69             Assert.AreEqual(theClass.Id, newUser.Class.Id);
70         }
71 
72         [TestFixtureTearDown]
73         public void TearDown()
74         {
75             ActiveRecordStarter.DropSchema();
76         }
77     }
78 }
79 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值