(若感觉以下思想存在问题,请速速离开!)
关于对象状态的维护,开始有所体会还是在linq2sql和ef中,称作上下文的应该就会对当前所使用过的对象进行状态跟踪,无论是新建对象,还是从数据库获取对象进而对其进行更新删除操作,在上下文中都会对它们进行状态跟踪。无论是简单对象还是包含子对象的复杂对象,都应该是有状态的。同样的思想,Csla框架中也是这么来处理的(当然,可以具体的处理方法不同)。
Csla框架中,状态的管理只对可编辑的对象有用,包括可编辑的根、子对象,可编辑的根、子对象集,还有一个就是动态可编辑对象。对于只读的对象本身就不具可编辑性,所以也谈不上状态了。
框架中的状态属性包括:IsNew,IsSelfDirty,IsDirty,IsSelfValid,IsValid,IsSavable,IsDeleted。其中在以前的版本中没有IsSelf与IsSelfValid,其展现形式是通过用户自己来实现的,在现在的版本中因为有了字段管理功能,所以这些功能就直接实现在了框架内部,比以前方便很多。也许从名称就可以看得出各个状态的意义,以下就个人看法作小小说明:
(状态不会独立工作,有些状态的依据是来自于其他某些的状态,如IsDirty与IsSelfDirty有关,是否可保存状态IsSavable与IsDeleted,IsNew等多个状态有关(当然也可能与对象的IsBusy状态有关);在保存时以上多个状态都会先后起作用!)
IsNew,顾名思义,代表新对象的意思,它标识如果内存中的对象主键存在于数据库中,那么值为False,否则值为True,在框架中创建新对象时默认为True,或者旧对象被删除后,系统也会将值赋予True(内在与数据库中主键不再对应)。在保存时,如果IsNew为True,系统会调用新增方法,否则就会是修改或删除。
IsSelfDirty(这个属性在看2.0版本时还没有),标识对象创建/获取后是否对其数据进行更新过(书上称为脏对象),所以无论是新建对象时还是对象重获取时,对象的脏状态默认是False的,当对象在对对象属性进行赋值或通过方法间接操作时,脏属性就会标识为True。IsDirty与IsSelfDirty大体一致,但IsDirty的状态还会与它的子对象的状态相关,也就是只有对象自身的IsSelfDirty为False并且所有子对象的IsDirty的状态为False时此对象的IsDrity才为False,否则当前的对象就是标识为脏的,所以每次访问该属性时它都会去遍历它的所有子对象的状态(当然如果有为True的就会直接返回),这个功能在旧版本中是在对象中通过重写IsDirty来实现的,在现在的版本中框架通过字段管理就可以自动进行跟踪(前提是属性中的子对象是通过框架内部的字段管理方式来实现的)。因为在IsDirty为False时当前对象(及子对象)是未编辑状态,所以为True时系统才会继续向下根据其他状态判断该执行什么数据操作方法,
IsValid与IsSelfValid与脏对象原理一致,只不过是否通过验证是根据对象的数据有效性有关,只有当前对象的所有字段都有效,也就是没有违反任何规则时才为True。数据有效性及验证规则的统一管理也是框架的一个实现目标,以后再说。
IsDeleted,标识当前对象是否被删除。框架支持直接删除和延迟删除,是否删除属性就是延迟删除进行操作的依据(注意的是子对象的的删除方法是DeleteChild(),根对象的为Delete(),不通用!),它会将当前可编辑的对象标识为IsDeleted=True,系统并不会直接提交,而是作删除标记,当用户最后调用Save()方法时系统会根据当前对象或子对象的删除状态进行调用删除方法。
最后的是IsSavable属性,它是以上属性的集合体,标识当前对象是否可保存,在这引用一下框架属性代码:
1: /// <summary>
2: /// Returns <see langword="true" /> if this object is both dirty and valid.
3: /// </summary>
4: /// <remarks>
5: /// An object is considered dirty (changed) if
6: /// <see cref="P:Csla.BusinessBase.IsDirty" /> returns <see langword="true" />. It is
7: /// considered valid if IsValid
8: /// returns <see langword="true" />. The IsSavable property is
9: /// a combination of these two properties.
10: /// </remarks>
11: /// <returns>A value indicating if this object is both dirty and valid.</returns>
12: [Browsable(false)]
13: public virtual bool IsSavable
14: {
15: get
16: {
17: bool auth;
18: if (IsDeleted)
19: auth = Csla.Security.AuthorizationRules.CanDeleteObject(this.GetType());
20: else if (IsNew)
21: auth = Csla.Security.AuthorizationRules.CanCreateObject(this.GetType());
22: else
23: auth = Csla.Security.AuthorizationRules.CanEditObject(this.GetType());
24: return (auth && IsDirty && IsValid && !IsBusy);
25: }
26: }
可以看出,除了上面的状态,还有auth和IsBusy,auth是获取对应状态下是否可操作的用户权限。至于后面的IsBusy,没注意过…
属性的应用主要是在页面状态的控制与数据保存,如当对象IsSavable为False时让保存按钮失效,当对象是新对象时可以禁用掉删除按钮,还有个主要应用点就是保存时,上面也提到,下面也贴下代码:
1: /// <summary>
2: /// Saves the object to the database.
3: /// </summary>
4: /// <remarks>
5: /// <para>
6: /// Calling this method starts the save operation, causing the object
7: /// to be inserted, updated or deleted within the database based on the
8: /// object's current state.
9: /// </para><para>
10: /// If <see cref="Core.BusinessBase.IsDeleted" /> is <see langword="true"/>
11: /// the object will be deleted. Otherwise, if <see cref="Core.BusinessBase.IsNew" />
12: /// is <see langword="true"/> the object will be inserted.
13: /// Otherwise the object's data will be updated in the database.
14: /// </para><para>
15: /// All this is contingent on <see cref="Core.BusinessBase.IsDirty" />. If
16: /// this value is <see langword="false"/>, no data operation occurs.
17: /// It is also contingent on <see cref="Core.BusinessBase.IsValid" />.
18: /// If this value is <see langword="false"/> an
19: /// exception will be thrown to indicate that the UI attempted to save an
20: /// invalid object.
21: /// </para><para>
22: /// It is important to note that this method returns a new version of the
23: /// business object that contains any data updated during the save operation.
24: /// You MUST update all object references to use this new version of the
25: /// business object in order to have access to the correct object data.
26: /// </para><para>
27: /// You can override this method to add your own custom behaviors to the save
28: /// operation. For instance, you may add some security checks to make sure
29: /// the user can save the object. If all security checks pass, you would then
30: /// invoke the base Save method via <c>base.Save()</c>.
31: /// </para>
32: /// </remarks>
33: /// <returns>A new object containing the saved values.</returns>
34: public virtual T Save()
35: {
36: T result;
37: if (this.IsChild)
38: throw new NotSupportedException(Resources.NoSaveChildException);
39: if (EditLevel > 0)
40: throw new Validation.ValidationException(Resources.NoSaveEditingException);
41: if (!IsValid && !IsDeleted)
42: throw new Validation.ValidationException(Resources.NoSaveInvalidException);
43: if (IsBusy)
44: throw new Validation.ValidationException(Resources.BusyObjectsMayNotBeSaved);
45: if (IsDirty)
46: result = (T)DataPortal.Update(this);
47: else
48: result = (T)this;
49: OnSaved(result, null, null);
50: return result;
Over!