2018/9/2

手刻 JQuery,Linq to SQL,AJAX , C# 做修改與刪除(Part1)

寫程式使用Ajax已經是十年前ASP的事,當時沒有其他框架輔助,傳輸資料走的是XML,組合資料相當不方便。以現在而言,不論前端或後端,將DB資料組成JSON傳遞與解析都已經非常方便了。以下的專案用一個ASP.NET WebForm當例子,實作Ajax顯示與更新資料。

WebForm常常被看作懶人程式,因為技術門檻低、拖拉控制項就會有結果。可是ASP.NET本身的ViewState以及操作往返暗地傳輸的資料,當畫面複雜時,速度就會變得笨重,許多顯示事件都放在後製程式碼中也不好閱讀。雖說 Asp.NET MVC更直接改善了責任分離與可維護性,但針對既有的Web Form專案,還是值得去改善她。

步驟一:資料來源
在專案引入Entity framework,選擇從資料庫更新模型。雖說網路上有許多大神推薦Linq to SQL,但以個人建議,除非自己是DBA而且對物件的命名、架構、關聯都有高度掌握,不然後續架構的變化,會讓模型突然跑出一堆編譯錯誤。Entity framework本來就只是個協助將資料庫物件反過來「物件化」的捷徑,若是資料非常龐大或結構複雜,應該好好想一下才對。

例如有一個資料表叫SCHOOL,裏頭有全台所有大專院校的資料,每校一筆且有索引鍵;這種形式的資料透過Linq to SQL存取就變得十分容易。我們用一隻泛型處理函式(.ashx)來顯示Linq從db抓出的資料,然後以JSON回傳給呼叫的前端。實務上還要考慮:回傳筆數是否加個上限,以免DB被操爆了,然後是否要限制這隻泛型處理函式適合被哪幾隻呼叫?需要在有登入的前提下才能呼叫他。

首先,因為考慮要判斷呼叫者的Session,所以.ashx的開端要加上繼承SessionState。

 public class GetOperator : IHttpHandler, System.Web.SessionState.IRequiresSessionState

然後,假設我們用學校代碼判斷回傳該校的人員,所以人員代碼要做點格式判斷。
在Ashx內讀取 Request,應該加上 context.Request。

 string shno = context.Request.Form["SCHOOL"];
            if (shno == null || shno == "" || shno.Length != 4) {
                context.Response.StatusCode = 404;
            }

接下來換 Linq to SQL 出場,用大括弧包住。
留意當中是用var 宣告一個泛型變數,在where的地方寫入篩選條件。
Linq 會將這種 Lambda語法轉譯成 SQL command,然後將回傳結果依照
Entity Framework的既有結構,轉成可列舉的物件,再選擇轉為List回傳。

可是有時候我們不想要Linq回傳所有欄位,
又或者有個欄位是需要處理過才能回傳的(如hash值),
像在SQL裡那樣直接Select as 成新欄位,或是做字串操作,可是常常會踢到鐵板。
因為Lambda有責任把動作轉譯給SQL,直接下在Lambda裡,會受到轉譯器看不懂的諸多限制,或是轉譯器認為SQL裡沒辦法這樣做,然後噴出錯誤。
以筆者的解決方法,會刻一個新的物件類別 SCHOOL_TO_SHOW,
告訴Lambda語法,將選定的欄位值抄到這個SCHOOL_TO_SHOW物件內,
回傳的是這個SCHOOL_TO_SHOW的集合,再轉成List,這樣後續的操作才不會報錯。

using (MyDbEntities Context= new MyDbEntities())
            {
var qq= Context.SCHOOL_OPERATOR.Where(o => o.SCHOOL_NO == shno).
                    Select(c => new SCHOOL_TO_SHOW
                        USER_ID =c.USER_ID,
                        USER_NAME = c.USER_NAME,
                        SCHOOL_NO = c.SCHOOL_NO,
                        ....
                    }).ToList();
}
SCHOOL_TO_SHOW的集合,欄位都是自己刻的,就不受到原來物件模型的限制,
可以透過 foreach 逐筆走訪去調整成自己要的樣子,最後透過JsonConvert.SerializeObject()的方法轉到前端,變成JSON字串。

                foreach (SCHOOL_TO_SHOW sw in qq) {
                    sw.USER_ID = sw.USER_ID.Trim();
                    sw.USER_ID_ENC = de.Encode(sw.USER_ID.Trim());             
                }
               string vq=  JsonConvert.SerializeObject(qq);
               context.Response.Write(vq);

接下來,就可以在VS裡的中斷點,看到要回傳到前端JSON的具體內容及欄位了。


步驟二 資料讀取
接下來我們用ajax 來讀取剛剛寫好的泛型處理函式。請留意範例程式碼內的url 要寫真正.ashx發布後的路徑 不然找不到資料就頭大了。
data:{ } 裡面是要post給 ashx的索引資料,告訴他要取那些資料回傳。
dataType: "json",  表示預計要回傳的是json資料。
這個範例有使用asp.net的 master page,所以所有控制項的名字在輸出時會被改名,
用JS存取時要特別留意。
success: 是順利取得資料後要做的事。在範例中,是針對一個空的表格,變成一列列的表格列,append到當中顯示。
這裡用到 data-toggle 的標記去觸動bootstrap 的modal語法,顯示交談框;另外加上onclick事件,以決定點擊按鈕後的行為。class設定為 btn。

   function readData() {
        $.ajax({
            url: "../WebComponent/Balabala.ashx",
            type: "POST",
            data: {
                SCHOOL: $('#ContentPlaceHolder1_DropdownList1').val(),
                HVERIFICATION: $('#ContentPlaceHolder1_HV').val()
            },
            dataType: "json",
            success: function (response) {
                $('#tb1 tbody').empty();
                $.each(response, function (index, element) {
               
                     $('#tb1 tbody').append(
                             $('<tr>'),
                             $('<td>' + element.USER_NAME + '</td>'),
                             $('<td>', { text: element.USER_ID }, '</td>'),
                             $('<td>', { text: element.DEPARTMENT }, '</td>'),
                             $('<td><input type=\"button\" class=\"btn btn-info\" value=\"修改\" data-toggle=\"modal\" data-target=\"#exampleModal\" onclick=\"fnUpd(\''+element.USER_ID_ENC+'\');\" ></td>'),
                             $('</tr>')
                             ) ;  
                });
            
            },
            error: function () {
                alert("LOAD ERROR!!!");
            }
        });
    
    }