我们已经准备好了环境,下面我们就来介绍CSLA业务对象的创建,如果你还没有下载CSLA,请在这里下载CSLA.NET ,我们使用的是3.8.2版本(本来想使用4.0版本,后来发现是针对framework 4.0的)。
建立类库项目CSLADemo.Library,引用下载的Csla.dll和 System.Windows.Interactivity.dll(CSLA依赖),另外还需要引用我们的linq项目。在这一节我们先介绍CSLA业 务对象一些基础的东西的实现,在这里包括业务属性,基本业务方法,基本数据验证,以及基本的数据门户.
在这之前,先介绍一下CSLA的其中的几个主要的业务基类:
Csla.BusinessBase 所有可编辑的业务类都要继承的基类
Csla.BusinessListBase 所有可编辑的业务集合类都要继承的基类
Csla.ReadOnlyBase 所有只读的业务类都要继承的基类
Csla.ReadOnlyListBase 所有只读的业务集合类都要继承的基类
使用之前版本的CSLA时,都是直接继承这几个基类,现在的版本已经利用泛型对这些基类进行了封装。我们以产品(Product)业务类为例来新建一个业 务类,在这里有个建议,如果你的项目比较大,而且多人维护,或者是由代码生成,你可以考虑用partial类,这样可以将生成的代码与自定义的代码分开, 或者是分成业务方法,工厂方法,数据门户等几个不同的分布类文件,这样也会方便源代码管控。
我们添加Product的三个属性:
[Serializable()]
public class Product : BusinessBase<Product>
{
#region Business Methods
private string aa;
private static PropertyInfo<string> ProductIDProperty =
RegisterProperty<string>(p => p.ProductID, "产品编号");
public string ProductID
{
get { return GetProperty(ProductIDProperty); }
set { SetProperty(ProductIDProperty, value); }
}
private static PropertyInfo<string> ItemNoProperty =
RegisterProperty<string>(p => p.ItemNo, "产品编号");
public string ItemNo
{
get { return GetProperty(ItemNoProperty); }
set { SetProperty(ItemNoProperty, value); }
}
private static PropertyInfo<string> ItemNameProperty =
RegisterProperty<string>(p => p.ItemName, "产品名称");
public string ItemName
{
get { return GetProperty(ItemNameProperty); }
set { SetProperty(ItemNameProperty, value); }
}
public override string ToString()
{
return ProductID.ToString();
}
#endregion
}
这可和我们的通常使用的简单实体的属性差别很大,甚至和之前版本都不一样,有几点需要注意:
1.类必须打上Serializable标签,因为整个对象是需要序列化传输的。
2.因为Product是单个可编辑的业务基类,所以直接继承BusinessBase<T>
3.同时使用了私有变量和属性,而且私有变量必须是static,这样能够保证在对象调用之前已经注册PropertyInfo,当然你可以在构造函数里 面调用RegisterProperty,不过不推荐这样。主要原因是如果是非静态变量注册PropertyInfo,你的默认序列化时也会报错,另外使 用静态变量可以节约内存,因为对于不同的实例来说,这些注册的属性信息也都是一样的。 详细讨论
4.之前版本是通过属性上打标签的方法,通过反射来获取属性信息,而现在是通过直接PropertyInfo,通过 FieldDataManager/PropertyInfoManager来管理,其中还将PropertyInfo列表缓存,主要是为了提供性能。
5.可以提供PropertyInfo类型的信息包括属性类型,属性友好名称,默认值,关系类型等,而这些信息都会被CSLA直接使用(见下代码).
6.每个属性的set,get都通过基类的GetProperty,SetProperty来实现,在读取和设置的过程中,其实是进行了权限的判断,判断对当前属性是否有相应的读或者写的权限.我们来看下GetProperty的部分源代码:
-
protected P GetProperty<P>(PropertyInfo <P> propertyInfo, Security.NoAccessBehavior noAccess)
-
{
-
P result = default (P);
-
if (_bypassPropertyChecks || CanReadProperty(propertyInfo.Name, noAccess == Csla.Security.NoAccessBehavior .ThrowException))
-
result = ReadProperty<P>(propertyInfo);
-
else
-
result = propertyInfo.DefaultValue;
-
return result;
-
}
7.另外一点,属性友好名称friend Name,如果有多语言需求,可以通过获取资源来实现.
至于关系属性,SmartDate这些我们在遇到时再介绍,我们接着添加产品的验证规则,先只添加对编号,名称不为空的校验,以及长度的限制:
-
#region Business Rules
-
protected override void AddBusinessRules()
-
{
-
ValidationRules.AddRule(Csla.Validation.CommonRules .StringRequired, new Csla.Validation.RuleArgs (ItemNoProperty)); ValidationRules.AddRule(Csla.Validation.CommonRules .StringMaxLength, new Csla.Validation.CommonRules .MaxLengthRuleArgs (ItemNoProperty, 50));
-
ValidationRules.AddRule(Csla.Validation.CommonRules .StringRequired, new Csla.Validation.RuleArgs (ItemNameProperty));
-
ValidationRules.AddRule(Csla.Validation.CommonRules .StringMaxLength, new Csla.Validation.CommonRules .MaxLengthRuleArgs (ItemNameProperty, 200));
-
}
-
#endregion
基类里面维护了一个ValidationRules属性,专门存储验证规则,我们直接向这个集合里添加就行了,添加的规则可以是通用的一些规则,在 CommentRules下面,有最大值最小值,长度,正则等通用规则.也可以是自定义自己的规则,比如我们需要规定所有的产品编号必须以字符开头,否则 保存或者更新不成功:
-
private static bool ItemNoRule<T>(T target, Csla.Validation.RuleArgs e) where T : Product {
-
if (!string .IsNullOrEmpty(target.ReadProperty(ItemNoProperty)) && !char .IsLetter(target.ReadProperty(ItemNoProperty)[0]))
-
{e.Description = "编号必须以字母开头!" ; return false ; } else { return true ; } }
这样当我们更新或者保存产品时,如果产品编号不是以字符开头,就会出异常,在业务对象的BrokenRulesCollection属性里加入导致失败的规则,我们可以直接查找到描述的错误信息。具体CSLA在内部是怎么调用的,我们会在后面介绍。其实之CSLA之所以让你感觉他的属性,他的业务方法,数据门户,业务规则,权限之间相互比较解耦,是因为他们之间的调用已经在框架部门,在CSLA的代码里面内部调用了 。好了,睡了,今天就到这里,下一节添加数据门户的实现和基本工厂方法。