當持久化物件時,顯然必須存在把記錄的值賦值到物件屬性和取得物件屬性的值用於持久化操作,對於更新操作,還需要檢查物件的值是否已發生變化,即是否為dirty,這些操作都是由物件的持久化類來完成的。有關持久化類可參考《會話和持久化操作》一文。
下面對nh的原始碼進行分析,以了解nh中資料載入和更新的過程。
一、持久物件載入
先來想像一下物件的載入過程(load).
1. 根據物件id從資料庫取得記錄;
2. 使用預設的建構函式構造乙個物件;
3. 把記錄的值儲存在乙個地方,用於在儲存時進行比較;
4. 把記錄的值賦值給物件的屬性。
在本文的前篇中已經分析了物件載入過程的前半部分,這裡僅對後半部分進行分析。
//*** entityloader.cs 34行 ***
public object load(isessionimplementor session, object id, object obj) , idtype, obj, id, false);
if (list.count==1)
else if (list.count==0)
else
}當使用session.load載入物件時,最後將呼叫物件持久化類的load方法。
//*** loader.cs 745行 ***
protected ilist loadentity( isessionimplementor session,
object values, itype types, object optionalobject,
object optionalid, bool returnproxies)
直接呼叫dofind。
private ilist dofind(
isessionimplementor session, object values,
itype types, object optionalobject,
object optionalid, persistentcollection optionalcollection,
object optionalcollectionowner, bool returnproxies,
rowselection selection, idictionary namedparams,
idictionary lockmodes)
else
ilist results = new arraylist();
idb***mand st = null;
// 解析查詢字串並生成idb***mand.
st = prepare***mand(
values, types, namedparams, selection, false, session);
idatareader rs = getresultset(st, selection, session);
try
substitute = substitute || intercepted;
if(status == status.loaded && persister.implementsvalidatable)
object updatedstate = null;
if(status==status.loaded)
updates.add(
new scheduledupdate(entry.id, values, dirtyproperties, entry.version,
nextversion, obj, updatedstate, persister, this)
);} }}
}首先取得屬性的值,這個通過物件的持久化類的getpropertyvalues方法來獲得,這個方法與前面設定物件屬性的setpropertyvalues是相反的;
然後查詢已更改的屬性,nh把控制權交給了interceptor(***),在finddirty中,我們可以設定已發生更改的屬性,這看起來是個不錯的處理,例如:在字段級許可權中,可以根據許可權限制某些屬性不被更改。如果不進行處理,一定要記得返回乙個null值哦,這時由物件的持久化類來查詢已更改的屬性(finddirty方法),如果檢查出物件是髒的(dirty), 就進行後續處理。
接下來nh再次將控制權交給了interceptor, 這次呼叫的是onflushdirty, 這樣我們又得到了乙個處理物件的機會,至於能做些什麼,那就要看大家的想像力了,最簡單的就是記錄更新日誌log。:-)
注意這個方法有個返回值,預設是返回false, 如果你修改了values的內容,並且需要更新,那麼應返回true, 這將再次呼叫物件持久化類的finddirty方法,前提是你沒有自行處理interceptor的finddirty方法。
再接下來,檢查物件是否實現了ivalidatable(驗證)介面, 如有實現則呼叫ivalidatable.validate方法。強烈建議所有的持久物件都應實現ivalidable, 雖然可以在對映檔案中指定一些約束,但這些約束的處理顯然比在ivalidatable介面中處理要晚,乙個比較關健的是可以提供一致的資料校驗介面(如驗證失敗,丟擲乙個validateexception, 並附上驗證失敗的錯誤資訊),這樣在表示層或業務層只要乙個簡單的處理就可以了。
最後將物件加入更新集合中,等待下一步處理。
// *** session.cs 2392行 ***
private void execute()
catch (exception e)
}處理所有存放在任務集合中的物件。
// *** session.cs 2450行 ***
private void executeall(icollection coll)
if ( batcher!=null ) batcher.executebatch();
}遍歷coll, 然後呼叫iexecutable.execute方法進行真正的持久化操作。
// *** scheduledupdate.cs 33行 ***
public override void execute()
通過物件的持久化類進行更新操作。
// *** entitypersister.cs 998行 ***
protected virtual void update(object id, object fields, bool includeproperty,
object oldversion, object obj, sqlstring sqlupdatestring, isessionimplementor session)
catch (exception e)
}上面的**看起來有點怪,不過顯然是batcher(批處理器)尚未完成的**。
dehydrate用於把與字段對應的屬性值賦值到statement的引數中。
// *** session 2438行 ***
public void postupdate(object obj, object updatedstate, object nextversion)
}調整session實體集合中物件的狀態。
// *** session.cs 2852行 ***
private void postflush()
interceptor.postflush( entitiesbykey.values );
}呼叫***的postflush方法,傳遞會話中的所有實體。
資料更新的持久化操作到此就結束了,與我們設想的一點出入,就是最後並沒把最新的屬性值存入到實體集合中,只是更改了loadedstate和lockmode,
至於為什麼,就能給大家去思考一些吧?
nhibernate原始碼七 HQL資料載入
nh中,hql是乙個十分強大的物件導向的查詢語言,簡單的說,就是不需要使用實際的表名和列名來查詢資料,而改用類名和屬性。有兩種方式來執行hql資料載入,一種是直接使用isession的find方法,另一種是使用iquery介面。iquery介面提供了一些額外的設定,最重要的就是分頁了,這個和icri...
nhibernate原始碼分析之一 物件對映
1.持久物件對映檔案 關於持久物件對映檔案,這裡就不多說了,可參考nhibernate的例子和文件。2.對映資訊的讀取 通過configuration類,可以用多種方式讀取對映資訊,一些以add開頭的方法就是用來加入對映資訊的,這些方法最終將呼叫add xmldocument doc configu...
nhibernate原始碼分析之一 物件對映
1.持久物件對映檔案 關於持久物件對映檔案,這裡就不多說了,可參考nhibernate的例子和文件。2.對映資訊的讀取 通過configuration類,可以用多種方式讀取對映資訊,一些以add開頭的方法就是用來加入對映資訊的,這些方法最終將呼叫add xmldocument doc configu...