Kuick 重視設計期的便利與直覺,尤其是在資料存取方法上,今日就請您看看幕後是如何達成。
Kuick 以 Entity 為設計中心,集中商業邏輯,直接跟資料庫溝通。在停用 Transaction 時,可以全然乎略背後如何跟資料庫溝通,在啟用 Transaction 時,只需建立 TransactionApi 物件包覆處理區段,即使是呼叫其他方法也可達成。
<相關類別>
首先列出相關類別:
<何種操作需要使用 Transaction>
資料『新增』、『修改』、『刪除』操作時,依據需求啟用 Transaction,『選取』操作一律停用 Transaction。
<Api & TransactionApi>
TransactionApi 是 Api 的衍生類別 (Derived Class),僅額外處理 Transaction 相關內容。
停用 Transaction 的資料操作,是透過建立各自的 Api 物件完成後就關閉。
啟用 Transaction 的資料操作,是透過建立共用的 TransactionApi 物件,整個交易區段完成後再關閉
<交易區段>
這有 2 個問題需要解決:
1. 如何判斷目前在同一個交易區段內
以下程式碼摘錄自 Kuick.Data.TransactionApi.ScopeId property (包含在下一版本更新)
public static string ScopeId
{
get
{
try {
if(Current.IsWebApplication) {
if(null == HttpContext.Current.Session) {
return Utility.GetUuid();
}
return string.Concat(
HttpContext.Current.Session.SessionID,
":",
HttpContext.Current.Timestamp.Ticks.ToString()
);
} else {
return Thread.CurrentThread.ManagedThreadId.ToString();
}
} catch(Exception ex) {
Logger.Error(
"TransactionApi.ScopeId",
ex.ToAny()
);
return Utility.GetUuid();
}
}
}
為了達成呼叫其他方法也可包覆在同一個 Transaction 裡,這需考量如何界定交易區段範圍 (ScopeId):
網站系統:
網站啟動階段還未建立 Session 物件時,只能同時存在一個 Transaction,ScopeId 為 UUID。
網站建立 Session 物件後,每一個 Session 的不同 Request 只能同時存在一個 Transaction,ScopeId 由 SessionID 與本次 Request 的開始時間 HttpContext.Timestamp.Ticks 組合而成。
非網站系統:
非網站系統每一個執行緒只能同時存在一個 Transaction,ScopeId 為所在執行緒的視別子 Thread.ManagedThreadId。
2. 何時建立,如何取得,以及何時關閉交易
TransactionApi 實作 IDisposable 介面,所以可以使用 using 陳述式表示如下
using(TransactionApi api = new TransactionApi()) {
// code here ...
}
相關內容請參考 IDisposable 介面,以及 using 陳述。
TransactionApi 建立
專案程式主動於 using 陳述裡建立 TransactionApi 物件,物件產生後將存於 Dictionary<string, TransactionApi> _Transactions 集合裡。
TransactionApi 取得
透過 TransactionApi.InTransaction 判斷 _Transactions 集合裡是否存在目前 ScopeId 的 Transaction,有則取出無則建立新的 Transaction。
public static TransactionApi Scope(IntervalLogger il, string entityName)
{
lock(_Lock) {
TransactionApi ts;
if(!_Transactions.TryGetValue(ScopeId, out ts)) {
ts = new TransactionApi(il, entityName);
}
return ts;
}
}
TransactionApi 關閉
由 TransactionApi.Dispose 方法關閉,並清除 _Transactions 集合裡該項物件。
public void Dispose()
{
lock(_Lock) {
base.DoEnd(IntervalLogger);
if(_Transactions.ContainsKey(ScopeId)) {
_Transactions.SafeRemove(ScopeId);
}
if(_SelfLogger) {
IntervalLogger.Dispose();
IntervalLogger = null;
}
}
}
鐵人賽分享列表:Kuick Application & ORM Framework
開放原始碼專案:kuick.codeplex.com
直接下載原始碼:Kuick
下載相關文件檔:C# Code Conventions and Design Guideline
相關教學影片區:Kuick on YouTube