2012年12月31日 星期一

無所不在的 DropDownList 末日餘生 MVC 跨年修練計畫 第三彈

在第一彈卷末提到的巨大陰謀是什麼呢 現在要揭曉了!!

就是...

對你的客戶而言水跟加需求都是免費的

仔細瞧瞧目前的這個頁面 有沒有什麼東西很違和?

沒有下拉選單耶!!

這種事是無可能發生在現實生活中的

你的客戶愛下拉選單

客戶表示:這邊要下拉選單

客戶表示:那邊要下拉選單

客戶表示:這邊再多個下拉選單

客戶表示:那邊再多個下拉選單

客戶表示:更多的下拉選單

而我們也不得不喜歡下拉選單

因為總比讓客戶恣意的輸入文字方塊再任意的附加欄位驗證來得好



通常一個基本的下拉選單 意味著 DB 裡面有兩張 TABLE 並且有關係

真正 Insert 的時候 其實只是需要 key 值 像這樣

正打算很開心的改 DB 之前 但是別忘了目前是使用 Code First 來開發的 所以只要改 Model 就好了

心想果斷神技術完全風騷的時候 窩草 報錯了

當初自動生出來的 DbContext 有段註解 有提供解決方法

但是保哥表示:這是一種十分殘暴的方法 因為舊資料會跟你說吻別

請透過 package manager console 啟用資料庫轉移

由於不是這篇的重點 我只列出會用到的指令

http://www.dotblogs.com.tw/skychang/archive/2012/04/04/71276.aspx

啟用轉移:Enable-Migrations -ContextTypeName testMvcCodeFirst.Models.DBContext

轉移版本:Add-Migration 版本名稱

更新資料庫:Update-Database



搞定好 DB 之後 發現 VS 沒有自動幫我們生出 DropDownList 果然還是沒那麼神奇的事會發生

不過這也是好事 如果 VS 真那麼神 我們可能要丟了飯碗

改變如下

"編譯" 過後 執行一下 發現 驗證怎麼怪怪的 沒紅框 如果開始猛找 CODE 哪裡有錯有問題 就大錯特錯了 因為只是很單純的 沒有設 CSS 而已

加工一下 好看多了



但是還沒完呢 POST 還沒改

在這邊會有個 字串 轉型 成 Guilty 失敗 連帶驗證不通過的問題 這裡先用投機的法子先忽略 ._. (好孩子不要學 壞孩子也一樣)

但是...It Sucks, But it works!

加入 DropDownList 的頁面 就(暫時)完成囉 wwwwwwww





最後...新年快樂 2013

MVC Request 的奇幻漂流 末日餘生 MVC 跨年修練計畫 第二彈

在第一彈裡面 我仗著 VS 的威能 三兩下的搞定了 基本五VIEW

而我只是很快樂的截了一堆圖 根本沒寫什麼 CODE

這回要慢慢來欣賞 MVC 中 Request 的奇幻漂流

在這之前 我們先來看看 Controller 中的 奧秘

Controller 是整個 ASP.NET MVC 的交通樞紐

負責接收前端發送過來的 HTTP Request (GET 或 POST) 然後交給 Model 處理 處理完之後再決定返回哪個 Action

如果是 WinForm 中毒很深的末期患者 一開始可能 完全不知道 GET 跟 POST 到底啥是啥 啥要幹啥 啥又是啥 啥要是要幹啥

請遺忘微軟的大騙局 「postback」 這個東東吧

真相是...

表單 form method = post 的時候 submit表單 會走 POST 它會加密資料

其他時候 "幾乎" 都走 GET 它不會加密資料



基於秘密口訣:Model要肥、Controller要飄逸、View要蠢

Controller 請盡量只讓它作 接受跟回應 其他複雜的邏輯請交給 Model

但是我們看看 VS 自動幫我們產生的 Controller 雖然五臟俱全 但是把 DB Access 也混在其中了

碰巧 DB Access 的操作都很簡單 所以給人一種 放這在這邊寫好像很 OK

但是這種做法不可取 跟當初 WinForm 一個 Click 事件環遊宇宙幾千行一樣 義大利麵式的寫法 不可接受啊啊啊~

抽層絕對是降低效能的 但是那怕是犧牲效能 也要極盡所能的提升可維護性!

血輪眼的各位一定有發現 Details、Edit跟Delete的 GET Action 根本是一模一樣的重複程式碼 重複代碼不可接受啊啊啊~

一陣攪和之後 Controller 被大改造

只剩下單純的 參數傳遞 跟 決定回應的 Action

個人喜好 GET 放一邊 POST 放一邊 並且抽掉重複 CODE

現在依靠 CriminalHelper 類別 進行 DB Access



日後要增加查詢就改 CriminalHelper ,要改顯示內容就改 View , Controller 感覺上應該改變不大

另外 MVC 之所以可以這樣很神奇的 穿越來穿越去 是因為強大的 model binding 機制存在

這又是另一段 偉大的 奇幻之旅了

2012年12月30日 星期日

一秒看破 yield

其實這個東西老早在 N 年前 就看過高人的 CODE 裡面有出現 當年調查了一下

除了大喊yoooooooo~ 之外 根本不知道他在公啥小 果斷裝傻 沒關係長大以後就會懂了

什麼時候長大呢? 現在就長大了

我們先看看 MSDN怎麼說

MSDN表示:yield 關鍵字,表示它所在的方法、運算子或 get 存取子是 Iterator。 您使用 Iterator 對集合中的自訂反覆項目。

Iterator 是啥小? Google翻譯表示:迭代器

迭代器 是啥小? Wiki表示:迭代器(iterator)有時又稱游標(cursor)是程式設計的軟體設計模式,可在容器物件(container,例如鏈表或陣列)上遍訪的介面,設計人員無需關心容器物件的內容。

總算還是有人講地球話

簡單來說 就是整天在用的 foreach (傳回型別必須是 IEnumerable、 IEnumerable<T>、 IEnumerator或 IEnumerator<T>。)

其實 MSDN 這篇的範例還算滿好懂的

http://msdn.microsoft.com/zh-tw/library/9k7k7cf0.aspx

應用層面上 有時候我們需要 從一個集合中篩選小集合 或者 從查詢中篩選結果 或者 從條件判斷中篩選true條件

以往都這麼做 new 個 List<T> 然後 add add add~

而使用 yield 的話 則可以省省這個 List<T>

yoooooooo~ 太神奇了蘿絲



另一個比較實用的地方是 可以使用在 get 存取子

有時候我們 常常會有一些 固定不變的像是常數的數據組

以往都這麼做 一堆的列舉 一堆的陣列 一堆的產生List<T>物件的方法 姑且不論這個寫法好不好 光是有人惡搞的話 你就會發現整個專案 布滿無數重複的該方法

換成 yield 並把 Members 變成一個類別的唯讀屬性

要取得 Members 都只能透過特定的類別的屬性

ASP.NET MVC + Entity Framework Code First 極速開發 末日餘生 MVC 跨年修練計畫 第一彈

世界末日之前保哥新的 MVC 書 問世啦 之前沒中文書無法拜讀的藉口與到此為止啦

為了紀念這個風平浪靜的末日 小弟準備展開 「末日餘生 MVC 跨年修練計畫」

就醬~*w*~





這篇的主旨在於如何 靠 MVC + Code First 極速達成資料庫的 CRUD

聽起來很強大 但是說穿了 其實是 MVC 哈囉沃德級的 小伎倆 而且只是仰賴著 VS 跟 framework 的淫威

VS 表示:如果摳頂是要我們嘔心瀝血,那我就讓你們看見 IDE 的驕傲

廢話不說 就讓我們 看 ● 下 ● 去



首先 生個專案 選 MVC4 然後名字可以自己取耶 呵呵呵

選 網際網路應用程式 會有些範例程式碼 可以參考

檢視引擎(view engine) 就用很潮的 Razor

是 Razor 不是 Razer 唷 別搞錯了

這是他生出來的一拖拉庫東東 重點在 M V C 三個資料夾

然後很神奇的現在就能執行了 如果有玩弄一下還會發現連會員系統都有





接下來就是今天的重頭戲 Code First

顧名思義 就是先寫 Code 也就是 MVC 的 Model

假如有個案件登打系統 有個需要紀錄 罪犯資訊的頁面 而我們需要紀錄 姓名、年齡、建立時間

然後建立個 Controller 名字隨意但是 結尾必須是 Controller

因為是要靠 IDE 無恥產生範例 範本選 具有讀取/寫入動作和檢視、使用 Entity Framework 的 MVC 控制器

用地球的語言來說 就是幫你生好 CRUD 各種頁面

模型類別 (相當於TABLE) 當然就是選剛剛寫好的 Model

模型內容類別 (相當於DB) 選 新資料內容 會幫你取個預設名稱

然後就 碰! 各位觀眾 5個 View

執行一下發現 全都搞定了

Create頁 還包欄位驗證!

Index頁

Edit頁

Details頁

Delete頁



強大,神技術,IDE是可以拯救世界的,有木有?





然而這只不過是一開始賞賜的甜頭,殊不知接下來還壟罩著巨大陰謀,究竟會如何發展?就讓我們看下去

2012年12月25日 星期二

一秒看破 T-SQL 強大的 ISNULL() 函數

查詢最怕的就是沒法一次查出來

分幾次查 再用C# 乾坤大挪移 是個以快打快的大絕招

但是理想代碼的世界 這麼做是不好的 因為違背 SOC原則

在資料查詢層 進行了邏輯的演算 這還不包括 有可能加入一些排版的語法

如果所以必須練就出一擊斃殺式的 TSQL查詢 才能夠切的乾淨





然後是最近有人問我的一個查詢

需求如下

有兩張表 一張是訂單清單 一張是成本報價清單

兩者跟產品的關係是多對多

目的是給訂單標上成本

條件是 訂單日期 如果有 相符月份的報價 則填該日期報價

否則標最新的一個日期的報價



一開始我還不明題意的時候 直覺用 CASE 來搞 後來發現兩張表是多對多關係 CASE 不起來

最後的解法是依靠 我的愛將 ISNULL() 函數 來做子查詢


SELECT B.[PID],B.[Name],B.[Date],
ISNULL(
    (
        SELECT C.[Cost] From CostTable AS C
        WHERE B.[PID] = C.[PID]
        AND B.[Date] = C.[Date]
    ),
    (
        SELECT TOP 1 C.[Cost] From CostTable AS C
        WHERE B.[PID] = C.[PID]
        ORDER BY C.[Date] DESC
    )
) AS 'COST'
FROM BillTable AS B

aaa 跟 bbb 都有相符的報價 所以顯示對應的報價

ccc 兩筆 都無相符的報價 所以顯示最後的報價

2012年12月22日 星期六

signalR 實驗紀錄簿 第四彈 之 MapHubs

轉眼之前 signalR 從 alpha2 又變成了 rc1 版啦

進化的速度比我學習的速度還快 -.-"

而且 github 上抓下來的專案 竟然還沒法順利編譯 (或許只是我比較笨吧)

但是仍可直接 package manager console 輸入

Install-Package Microsoft.AspNet.SignalR.Sample

或直接 NuGet 安裝進專案

安裝完之後還會很貼心的附上一個 讀我.txt



讀我.txt? 讀你妹,小弟我不論軟體還是遊戲安裝完從不看這種東西的 尤其是寫歪果文字



於是我開始瀟灑的 果斷coderush~~~~

然後就被致死打擊

乍看之下是路徑錯了 試遍所有路徑 還是錯

讓我感受到十足的挫敗

原來是現世報 老師在講我沒有在聽

讀我.txt 明瞭的寫了 必須在 ApplicationStart 的時候 宣告 default hubs route

由於之前用的 遠古 0.5.3 版 預設就宣告好了 雖然可以自行更改

但是我從沒用過 更不用說改版還改了些東東

總而言之 現在必須自己指定好路徑 即是要用預設路徑 也必須附上 RouteTable.Routes.MapHubs();

最簡單的作法是寫在 Global.asax

但是這裡很髒呀 除了 Web.config 之外 這裡第二髒 人人都有可能在這裡挖洞給人跳

我不怕踩地雷 但是我怕別人把我的 必需品給丟了 ~.~



參考之前留下來的範例 果真有好招

自訂一個 靜態類別 並標記 PreApplicationStartMethod 特性(Attribute)

傳入兩個參數

第一個參數指定類別

第二個參數指名方法

他便會很神奇的自動在 ApplicationStart 的時候 執行 RouteTable.Routes.MapHubs();

2012年12月11日 星期二

一秒看破 T - SQL 多筆欄位合併

外表看似簡單難度卻異於常人的 T - SQL 這次又有什麼新難題呢?

就讓我們看下去

首先我有三張表 兩張 List 表 一張 Mapping 表

原先 Hyperlink 跟 Tag 的對應關係為多對多 但是為了符合正規化 拆成兩組 一對多的形式 非常常見

需求也還算合理 我想看到 每個 Hyperlink 對應的 TagName

但是我想要 不管有多少 TagName 都收錄於同一筆之中

各位看官如果沒有試過的話 不妨先自行嘗試一遍 如果輕易的就解開了 表示您已經是踢吸摳之神 值得瞻仰





就跟魔術一樣說穿了其實沒那麼難 主要需要 JOIN 跟 子查詢 這都不難想像

但是最難的應該就是這個合併成一行的 TagName

定番 估狗了一下 發現 FOR XML 子句

神人文:http://www.dotblogs.com.tw/chhuang/archive/2008/03/19/1926.aspx

簡單來說就是把查詢結果變成一行 XML 來表示

目前是針對單一比的合併 要跟 整張 Hyperlink 合併 就要借助子查詢了

但是身為具有偏執狂熱的PG 不可能允許 那個多餘的 逗點

使用 STUFF 函數 來搞定





備忘


SELECT Title, Url,
STUFF((
    SELECT DISTINCT ',' + T.TagName FROM Hyperlink AS H
    JOIN HyperlinkTag AS HT ON H.ID = HT.HyperlinkID
    JOIN Tag AS T ON T.ID = HT.TagID
    WHERE H.ID = Hyperlink.ID
    FOR XML PATH('')
),1,1,'') AS 'Tags'
FROM Hyperlink

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 使用方法

打完收工