2012年11月28日 星期三

靜態 DB access 類別 擴展 Transaction 的方法

關於 DB 操作 通常都會包成一個專用的類別 一來避免重複程式碼 二來分層結構降低耦合

所以我有個 accessDB.NonQuery() 方法 只要 傳入 SQL 指令 跟 SqlParameter 參數 即可完成 DB 操作 其他的細節被封裝在方法之中

但是你知道的 有些人會這樣搞 例如這樣 猜猜會怎樣?

毫不意外 碰! Exception 被顯示在 Label1 上

DB... WTF...

看一下原始碼 就知道為何了

先前的寫法 早就預設所有的方法都是一次性的叫用 也就是各自為一段獨立的 DB 操作

但是實際使用上通常都是先 INSERT 一下 SELECT 一下 運算一下 再 INSERT 一下

而搞完這一輪回 才算一次成功的 "交易"

顯而易見 我需要給每個 SqlCommand 包上 Transaction 如果要期望 呼叫的人把 Transaction 寫在 T-SQL 中 那我就太傻太天真了

但是我立馬遇到了挑戰...

1. SqlTransaction 只存活在 SqlConnection 一次的開關過程之中!! 詳洽 MSDN

2. 這是一個 靜態類別!! 我沒有辦法 設一個變數(靜態類別內只能有靜態變數)來記住 SqlConnection 或是 SqlTransaction 這樣會使得同時叫用的時候發生衝突

就算真的有辦法釋出 SqlConnection 或是 SqlTransaction 的話 另外的問題則是其開關變得無法控制

當初設計這個類別 就是為了封裝 DB 操作 防止外部變因介入 這麼做等於違背初衷

沒錯 我必須在 「不提對外提供 SqlConnection 或是 SqlTransaction」的前提下 完成 Transaction 的封裝

如果是從前的我鐵定會說沒計 不然就是改成一般類別 用 new 物件的方式 獨立執行個體 則沒有衝突的問題

但是現在的我不一樣了!! 因為未來的我坐著時光機到了現在告訴了我解答!! (P.S 據未來的我表示 時光機是跟某藍色生物借的)

答案就是 我可以使用強大的委派!!



首先 封裝 建立 SqlConnection 和 SqlTransaction 成一個私有方法 並完整的包覆整個開關和交易流程 唯有叫用這個方法 才會執行完整的 DB 操作

公開方法 UsingTransactionActions 方法 是一個接受型別為 Action 參數的方法

在該方法之中 封裝了實際取的 SqlConnection 跟 SqlTransaction 的實作 也就是透過呼叫私有方法 UsingConnection

在外部使用上 不需要知道 傳入參數由何而來 (也不允許被知道)

另外將原先的 accessDB.NonQuery() 方法增加一個多載 傳入 SqlConnection 跟 SqlTransaction

請注意 唯有使用 UsingTransactionActions 方法 才有辦法在其參數(委派方法)中得到 SqlConnection 跟 SqlTransaction

UsingTransactionActions 使用方法

打完收工

2012年11月26日 星期一

2012年11月22日 星期四

一秒看破T-SQL分頁 使用 ROW_NUMBER() 函數

分頁~分頁~分頁~

勞版表示:ㄟ~那個誰 這頁要分頁 那頁也要 我沒說不要的都要

這時候就發現 「有沒有 在勞版的指示過後 gridview 的自動分頁都突然失效了 的八卦」 是真的

身為悲催小PG 立當自強



首先是一般查詢語法 定番是北風

不管是這樣

SELECT P.ProductID
      ,P.ProductName
      ,S.CompanyName
      ,C.CategoryName
  FROM Products AS P, Categories AS C, Suppliers AS S
 WHERE P.CategoryID = C.CategoryID AND P.SupplierID = S.SupplierID

還是這樣

SELECT P.ProductID
      ,P.ProductName
      ,S.CompanyName
      ,C.CategoryName
  FROM Products AS P
  JOIN Categories AS C ON P.CategoryID = C.CategoryID
  JOIN Suppliers AS S ON P.SupplierID = S.SupplierID

都會得到一張 完全合體型態的 查詢結果 如果你的北風是原廠的 那結果應該會是 77筆資料



接下來我們利用 ROW_NUMBER() 函數

ROW_NUMBER() 函數 其實只是幫每筆資料作編號而已 為了從中挑出某某頁的 某OO ~ XX筆 必須再加工一次



SELECT PPI AS '產品哀低'
      ,PPN AS '產品念母'
      ,SCN AS '公司念母'
      ,CCN AS '分類念母'
FROM (

SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS ROW,
       P.ProductID AS PPI
      ,P.ProductName AS PPN
      ,S.CompanyName AS SCN
      ,C.CategoryName AS CCN
  FROM Products AS P, Categories AS C, Suppliers AS S
 WHERE P.CategoryID = C.CategoryID AND P.SupplierID = S.SupplierID

) AS NewTable
WHERE NewTable.ROW >= (@PageRows * @PageIndex) + 1
  AND NewTable.ROW <= (@PageRows * @PageIndex) + @PageRows

圖解

結果

2012年11月20日 星期二

signalR 實驗紀錄簿 第三彈 之 改版搶先試玩

前一陣子發現 NuGet 上找不到那熟悉的身影 原來 signalR 悄悄的正名啦

西格農R表示:請叫我 ASP.NET SignalR

雖然貌似還沒正式發行 必須切到包括發行前版本 才找的到

官網

定番,抓官方範例來玩 下載完只有 10MB 這是假象 記得啟用NuGet套件還原 編譯之後 立馬暴肥為 150MB

一樣一堆東西都看不懂 只能能玩玩 基本五式第一式 網頁聊天

一開始自以為很懂亂試 結果很鬱悶怎麼試都不成 看了範例才發現多了些東東 在這裡把該注意的重點寫下來



現在不管是呼叫還是接收 都多一層節點 來表明 server 還是 client 解決先前命名容易混淆的問題



$.connection.chat 跟 chat.server.send 一樣務必是小寫 即使C#類別是大寫開頭



現在 Hub 預設就能直接 override 連線 斷線 重連 三個方法 不在需要繼承介面再實作



意外的收穫是學到 jQuery.tmpl 雖然之前曾聞 jQuery 有個樣板啥的 但是不了了之

http://www.cnblogs.com/think8848/archive/2011/07/17/2108570.html

簡單來說 就是簡化了 將物件組合成 html 的過程





2012年11月9日 星期五

善用布林 - 增加 易讀 & 易維護 & 易傳承 系列 第二彈

這個是個討論增加 易讀 & 易維護 & 易傳承 並且絕對會犧牲一些效能的系列

布林 true false 程式設計師一定不陌生

但是其實它的用途不僅僅用於表示一個屬性的真假

既然寫在這個系列,顯而易見來看看怎麼用它來增可讀可維護性



首先來看看這個if

假設一個流程有5個步驟且順序固定,但是分別在 1 3 5 需要判斷 CheckBox 勾選狀態做分歧

這樣寫有錯嗎?當然沒錯,但是顯然不好

因為同樣的結果卻進行了三次的判斷

嫻熟的 PG 都知道當一個方法返回的結果會在複數地方使用到,可以用一個變數接起來,之後只要直接使用變數,不必每次呼叫方法以提升效能

if 其實可以當作成一個特殊的方法, () 內接的參數是布林值

雖然我們是丟一組值跟運算子的組合進去,但是程式語言很聰明的有辦法把塞進去條件轉換成布林值

所以同理任何 if 判斷出的結果,都可以用布林型別的變數接住,之後不必再進行判斷

雖然看起來還是用了3個 if ,但是實際上只進行了一次的運算,後面都直接取得布林值沒有進行運算



再來還是看看if

這個情況其實不少見,在判斷某某值之前必須先判斷是不是 null

條件少的時候還 OK ,但是有時候必須判斷多個值...這時候如果又沒折行排版的話,就會看到比萬里長城還長的一條if

試試這個

2012年11月1日 星期四

善用陣列 - 增加 易讀 & 易維護 & 易傳承 系列 第一彈

這個是個討論增加 易讀 & 易維護 & 易傳承 並且絕對會犧牲一些效能的系列

通常一組功能按鈕由於常常在各處使用,為了避免重複程式碼,不管是做成使用者控制項還是利用樣板來使按鈕組唯一都是常見的做法

但是共用謂之必須判斷所有的情況,因為實際上有很多因素左右這些按鈕的行為

像是新增頁不該出現[查看],查看頁不該出現[儲存]等等的顯而易見的邏輯互斥

為了在各種情況下判斷按鈕的顯示,不知不覺就寫了這串CODE

如果各位看官覺得這串東西,很簡單明瞭,對應十分分明的話,恭喜您絕對是擁有血輪眼

到底要怎樣才能既明瞭又能避免多次的宣告Visible呢?

早在標題就說破謎底了,就是使用陣列

陣列不但可以整齊的整理這組按鈕之外

更重要的是它可以foreach

嫻熟的PG都知道不管怎樣重複類似相近的鬼東西,想辦法用迴圈,就對了

這裡使用了一組Button[] 跟 各種情況顯示與否的 bool[]

最後不論過程如何 只需要 for迴圈 媒合 Button[] 跟 bool[] 即可

雖然我不知道這樣是否有比較乾淨明瞭,至少我是信了。

雖然這邊刻意對齊排版讓邏輯變得視覺化,但是實際上保持一致的寫作風格就好了

以上。