(若感覺以下思想存在問題,請速速離開!)
關於對象狀態的維護,開始有所體會還是在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!