顯示具有 C# 標籤的文章。 顯示所有文章
顯示具有 C# 標籤的文章。 顯示所有文章

2018年3月29日 星期四

使用 LinqPad 快速產生 Dapper 所需要的 SQL 語法 - Class、Insert、Update

前言

工作上目前已經很習慣用 Dapper 這種輕型的 ORM 來處理有關DAL層的應用,但相較於 Entity Freamwork,在處理新增/更新時就比較沒那麼方便,主要差異在Entity Freamwork 可以直接用物件操作的方式來做資料庫異動,而Dapper就必須寫SQL Commend,雖然有一些Open Source Extentions 已經封裝這些邏輯,譬如:SimpleCRUD﹉等,但實際使用常常得依規範設定一些屬性,有時發生錯誤時也不是那麼的直覺,故目前我還是會以SQL Commend為主。但產生Commend是一件麻煩事,如果搭配 Linqpad 寫一個Script 可以依需求快速產生所需要的commend,彈性是很大的,此篇文章介紹我在實務上我常用Scripts,來快速產生相關 SQL Commend

如何設定LinqPad

20180311_015834

Step 1 : 這邊可以直接瀏覽資料庫的Schema
Step 2 : 這邊使用C# Program 來撰寫我們要產生Script的程式
Step 3 : 選擇資料庫的連線字串

接著以下是我常用的Helper,只要貼到內容裡面即可產生


 

void Main()

{

 this.Connection

 .DumpClass(@"

SELECT * FROM Table

 ","ViewModelName")

 .Dump();

}

// Define other methods and classes here

public static class LINQPadExtensions

{

 private static readonly Dictionary TypeAliases = new Dictionary {

 { typeof(int), "int" },

 { typeof(short), "short" },

 { typeof(byte), "byte" },

 { typeof(byte[]), "byte[]" },

 { typeof(long), "long" },

 { typeof(double), "double" },

 { typeof(decimal), "decimal" },

 { typeof(float), "float" },

 { typeof(bool), "bool" },

 { typeof(string), "string" }

 };

 private static readonly HashSet NullableTypes = new HashSet {

 typeof(int),

 typeof(short),

 typeof(long),

 typeof(double),

 typeof(decimal),

 typeof(float),

 typeof(bool),

 typeof(DateTime)

 };

 public static string DumpClass(this IDbConnection connection, string sql,string Name)

 {

 if(connection.State != ConnectionState.Open)

 connection.Open();

 var cmd = connection.CreateCommand();

 cmd.CommandText = sql;

 var reader = cmd.ExecuteReader();

 var builder = new StringBuilder();

 do

 {

 if(reader.FieldCount <= 1) continue;

 builder.AppendLine("public class " + Name);

 builder.AppendLine("{");

 var schema = reader.GetSchemaTable();

 foreach (DataRow row in schema.Rows)

 {

 var type = (Type)row["DataType"];

 var name = TypeAliases.ContainsKey(type) ? TypeAliases[type] : type.Name;

 var isNullable = (bool)row["AllowDBNull"] && NullableTypes.Contains(type);

 var collumnName = (string)row["ColumnName"];

 builder.AppendLine(string.Format("\tpublic {0}{1} {2} {{ get; set; }}", name, isNullable ? "?" : string.Empty, collumnName));

 }

 builder.AppendLine("}");

 builder.AppendLine(); 

 } while(reader.NextResult());

 return builder.ToString();

 }

}


產生 Insert 語法



void Main()
{
 // SQL Command
 var sqlCommand = @"SELECT top 1 * FROM dbo.Table WITH (NOLOCK);";
 
 this.Connection.GenerateInsertCommand(sqlCommand.ToString(), "Table").Dump();
 
}
 
public static class LINQPadExtensions
{
 public static string GenerateInsertCommand(this IDbConnection connection, string sql, string tableName = "TableName")
 {
 if (connection.State != ConnectionState.Open)
 {
 connection.Open();
 }
 
 var cmd = connection.CreateCommand();
 cmd.CommandText = sql;
 var reader = cmd.ExecuteReader();
 
 var builder = new StringBuilder();
 do
 {
 if (reader.FieldCount <= 1)
 {
 continue;
 }
 
 builder.AppendFormat("INSERT INTO [dbo].[{0}]{1}", tableName, Environment.NewLine);
 builder.AppendLine("(");
 
 var schema = reader.GetSchemaTable();
 var columnNames = new List();
 
 foreach (DataRow row in schema.Rows)
 {
 var columnName = (string)row["ColumnName"];
 columnNames.Add(columnName);
 }
 
 foreach (var columnName in columnNames)
 {
 builder.AppendFormat(" [{0}]{1}{2}",
 columnName,
 columnNames.IndexOf(columnName).Equals(columnNames.Count - 1) ? "" : ",",
 Environment.NewLine);
 }
 
 builder.AppendLine(")");
 builder.AppendLine("VALUES");
 builder.AppendLine("(");
 
 foreach (var columnName in columnNames)
 {
 builder.AppendFormat(" @{0}{1}{2}",
 columnName,
 columnNames.IndexOf(columnName).Equals(columnNames.Count - 1) ? "" : ",",
 Environment.NewLine);
 }
 
 builder.AppendLine(");");
 builder.AppendLine();
 }
 while (reader.NextResult());
 
 return builder.ToString();
 }
}


產生 Update 語法


void Main()
{
 // SQL Command
 var tableName = "TableName";
 var sqlCommand = @"SELECT top 1 * FROM [dbo].["+tableName+"]";
 
 this.Connection.GenerateInsertCommand(sqlCommand.ToString(), tableName).Dump();
 
}
 
public static class LINQPadExtensions
{
 public static string GenerateInsertCommand(this IDbConnection connection, string sql, string tableName = "TableName")
 {
 if (connection.State != ConnectionState.Open)
 {
 connection.Open();
 }
 
 var cmd = connection.CreateCommand();
 cmd.CommandText = sql;
 var reader = cmd.ExecuteReader();
 
 var builder = new StringBuilder();
 do
 {
 if (reader.FieldCount <= 1)
 {
 continue;
 }
 
 builder.AppendFormat("UPDATE [dbo].[{0}] SET {1}", tableName, Environment.NewLine);
 // builder.AppendLine("(");
 
 var schema = reader.GetSchemaTable();
 var columnNames = new List();
 
 foreach (DataRow row in schema.Rows)
 {
 var columnName = (string)row["ColumnName"];
 columnNames.Add(columnName);
 }
 
 foreach (var columnName in columnNames)
 {
 builder.AppendFormat(" [{0}] = @{0}{1}{2}",
 columnName,
 columnNames.IndexOf(columnName).Equals(columnNames.Count - 1) ? "" : ",",
 Environment.NewLine);
 }
 
 builder.AppendLine("WHERE ID = @ID");
 }
 while (reader.NextResult());
 
 return builder.ToString();
 }
}

2014年10月4日 星期六

[鐵人30天]當ASP.NET MVC 遇見 Angular.js MVC 客戶管理系統(7) - 取得WebAPI資料(Angular.js)

* 本篇目標

利用Angular.js像WebAPI取得資料

* 前言

以往開發前端多半倚賴jQuery,今年接觸到了Google所推出的JavaScript libery , 他是一個前端MVC的Freamwork,Study過後,認為將前端改寫成NG,程式會比較有彈性,故開始投入學習。個人認為學習曲線NG比學習jQuery還要高,本系列文章並不是針對NG做一個詳細介紹,故會採用"做中學"的方式,來實作ASP.NET MVC如何搭配Angular.js做開發。

* Visual Studio 安裝

我們一樣在Web專案使用Nuget安裝

4ae8c68e39ce4cca9b2fe982736d2a4f

會看到Scripts資料夾裡有非常的多的Angular套件,這是因為Angular.js模組化做得非常好,故如果沒有要用到的功能,就不用載入進來,而相關的模組有什麼功能可以用,其實可以google ng加檔名,就可以查到官方文件或文章,如 “ng-resource”。

e7f4127b09af48a0bdd1a59b23ba2450

接著我們打開MVC的 View,Shared資料夾_Layout.cshtml檔案,載入angular.min.js。

_Layout有點像是ASP.NET WebForm的Master Page,可以把一些共用的html,js,css放在這,頁面各自的View就不用存在於重複的程式碼 e.g 選單列。

4280682be0ba4eee9669dd2e0d31bb20

* 修改CustomerController

上一篇我們取得WebAPI資料的方式,是採取C# WebClinet的方式,在Contoller轉成ViewModel在給View,採用Angular.js將會做一些小修改。首先我們將程式碼註解起來。

219dc17ca88d4f54a3c278980a068d79

接著我們改寫View使用Angular.js的語法,會發現Visual Studio 2013 已經很貼心的將NG的語法變為紫色了,這讓開發更加的清楚,以下依步驟做介紹

ng-app : 可以說是Angular.js的起始點,子元素才會看得懂Angular.js的語法

ng-controller : 因為是MVC架構,故我們會在Scripts新增一個Controller的function,並指定這個Div使用CustCtrl

$scope : 可以想成是"前端"的ViewModel,又有點像是C#的Class,可以將變數定義在此,以此例,我們將後端取回的Customer JSON資料,丟給$scope裡的Customer。

$http : 在與後端資料溝通,我們可以使用$http來對Server API進行,POST . GET . PUT .DELETE,以此例我們向我們WebAPI取得資料,丟給$scope裡的Customer;失敗的話則給$scope一個變數error,並秀在Div裡。

$ng-repeat : 此語法可以讓我們很輕鬆的寫出迴圈功能,如Customer裡面的資料,我們將資料一筆一筆讀出來,並變成html table裡的tr列。

8c326a0bc5104c188986a7d4ab413b1e

結果畫面

07a6757c363749109aabd426f4892e7a

* 雙向繫結

在Angular.js的MVC架構,都有Data Binding的特性,也就是今天在Model改變了一些值,或在View改變了一些值,是兩方都會產生變化的。

image

用講的不太清楚,故我們來玩個小範例:

http://jsfiddle.net/kyleshen/5un6argf/

TestCtrl裡面Model有 Day . Name兩個變數,及一個事件 Add,將Day加1

ng-model : 可以指定這個input標籤 對應到Model的名稱

ng-click : 點選Click的時候去執行哪個事件

08cc1b432f954b36b1e13e27d00ef5fb

* 後記

此篇介紹了一些Angular.js的一些基本用法,下一篇預計來換個輕鬆主題,來介紹如何利用一些工具來快速美化我們的網站。

Angular.js逐步學習文章推薦:

男丁格爾Angular.js教學 http://abgne.tw/category/angularjs

黑暗執行緒Angular.js系列 http://blog.darkthread.net/blogs/darkthreadtw/archive/tags/AngularJS/default.aspx

 

 

本系列程式原始碼請至我的Github下載  https://github.com/kyleap

** 如內容有誤請告知,將進行修改,謝謝 **

2014年10月3日 星期五

[鐵人30天]當ASP.NET MVC 遇見 Angular.js MVC 客戶管理系統(6) - 取得WebAPI資料

* 本篇目標

建置一個RESTful風格的Web服務

* Web API 2.2

現在開發通常會考慮到多平台,如手機平板等等,但關於資料來源不可能針對每個平台都去寫一樣的Code,早期.NET解決方案有Web Service、WCF Service的應用,.NET Freamwork 4.5後推出了更輕量化的Web API服務,搭配MVC架構開發上變得非常的輕鬆,本系列文章使用Web API 2.2。

延伸閱讀  [Web API] 初探 Web API 筆記

* 建置Web API

我們再UI層新增Web專案時,其實就已經勾選安裝Web API了,如果忘記選擇了,可以透過Nuget安裝。

a8dcf173f2614837b442e02a913799a9

WebAPI開發習慣,我通常會再專案底下建一個API資料夾,接著點選右鍵,加入Web API控制器

f247eb1d2af848babad98b146db3126a

建立以後,她預設會幫我們建立CRUD function,我們就針對每個function去改寫,注意Web API也是MVC架構,命名也是為Controller結尾,但不同的是Web API是繼承ApiController。

9c6601b5d9a54583bdc1d37aab8aae37

接下來我們將Get稍作修改,向BLL層要客戶資料,HttpReponseMessage可以很方便的讓前端知道是否有發生錯誤,並回傳自己定義的Object。

7b24c666c2444fae98ab71461d75553d

接著在瀏覽器執行,輸入 host/api/Customer即可取得我們的資料

a109f7e377e44ef48a866cb63d5a45ad

* 於MVC的Controller及View列出資料

接著我們再專案裡Contoller,新增一個CustomerController

e7bede476978464188a15b911f382cc7

在Controller使用WebClinet像Web API要資料

3dded709ab774d879f9ecd1cf1d1df83

在新增一個View,套入原本樣板的主體Layout

b47227cee9764b49a4fcc1a2ebd5c62b

使用ViewModel,並用好用的Razor語法印出資料

39321e5640db412282e6ee4a0567e661

結果畫面

8dc19f6dfc0745b28cd4d067c85db1f5

* 後記

我認為Web API是個趨勢,未來我也一定會採用這種架構,一方面MVC的Contoller不會有太多跟BLL Service溝通的code,且對於多專案平台,都可向WebAPI取得資料。但實務上我並不會將跟Web API的Code寫在Controller裡,而會是在前端的View,也就是Angular.js登場的時候了!

延伸閱讀ASP.NET MVC - 第一個Web API,Hello Web API

ASP.NET WEB API 心得筆記 (4) WEB API ROUTING

MSDN – MVC Razor語法

 

本系列程式原始碼請至我的Github下載  https://github.com/kyleap

** 如內容有誤請告知,將進行修改,謝謝 **

2014年10月2日 星期四

[鐵人30天]當ASP.NET MVC 遇見 Angular.js MVC 客戶管理系統(5) - 打造 BLL層

* 本篇目標

建立BLL(Business Logic Layout) ,建立ViewModel,將Entity物件轉為ViewModel給前端使用。

* 關於ViewModel

將DAL層及Domain層加入參考

aaa8beeacba34b2c9c45e5cd74a45963

上一篇加入實體模組,Entity Freamwork已經會自動幫我們產生Model的Class,我們在Domain方案再新增一個資料夾叫ViewModels,並新增一個CustomerViewModel

135e941e57c7410c9e02d3808b6ad781

 

通常我會將Customer.cs 欄位內容先全部複製到CustomerViewModel.cs

181845689e294e73802108ca4a141503

為何要這樣 ? 好像只是多複製了一遍…。其實ViewModel初步設計可以從妳的View出發,表單有什麼欄位就該有什麼 property,譬如一個登入頁面,可能有帳號(Account)、密碼(Password)欄位,但實際上使用者資料表,可能有存在其他欄位入IP位置,建立日期,建立人員…等等欄位,這些欄位再View那邊是用不到的,所以我們不用把那麼大包的資訊再前後端穿梭,這就是ViewModel的用意。

* BLL建立Service

接著我們會到BLL層,建立一個Services資料夾,並加入一個CustomerService.cs,我們再建構的時候使用DAL層的Repository,因為泛型的關係,我們可以直接指定這個Repositoy使用Customers資料表

1645d723925841b6809b866b651505c8

接下來我們建立一個方法,取得所有客戶資料,將DAL取出的客戶資料跑迴圈丟進我們的ViewModel並回傳

d8e3aecd2a6545248d0d8ceaa52724da

但如果欄位有20.30個,要一個一個塞也太累了....這時候就是AutoMapper出場的時候

* 使用NuGet安裝AutoMapper

使用Visual Studio開發.NET,最大的重點就是生產力極高,有很多的Freamwork及Plugin,我們可以透過Nuget來下載,使用方式是在專案上點右鍵,點選管理Nuget套件。

再搜尋欄位輸入AutoMapper,點選安裝

1978ea67073e4ae9925555739320127e

接著我們再改寫一下Get function

d2fa464b055343d595b1315ad6ad000a

程式碼是不是簡潔很多,AutoMapper會自動幫我們做完轉換的動作,不用再自己刻了,這套件還有很多強大的功能,這邊就不一一做介紹了!

* 後記

我們已經完成Domain、DAL的建置,並完成呼叫DAL取得DB資料,並轉換成我們需要的ViewModel,接下來下一篇就來講解,前端UI層,怎麼跟BLL溝通取得ViewModel。

2014年2月16日 星期日

Visual Studio 2013–C#.JavaScript outline,一個摺疊程式碼(if else or for each)的小套件

這幾天發現一個小套件對Debug還蠻實用的,可以將程式碼摺疊起來,看程式邏輯時就會比較方便

安裝方式可透過Nuget

1111

Visual Studo 2010/2012也有支援,詳細效果與版本介紹可擴充功能頁面查看

http://visualstudiogallery.msdn.microsoft.com/6c3c5dec-1534-4c42-81b1-cfd4615fd0e9

至於Javascript則可下載 JavaScript outlining

1111

2014年1月28日 星期二

C# Win Form如何利用GotFocus和LostFocus事件來變更焦點focus於button的樣式

看到論壇問到,因為User在操作系統時常常用tab鍵+enter來快速操作,但預設的focus只會在button上有虛線邊框,有時因為螢幕的因素可能會看不清楚,故希望focus的button能清楚明顯一些,而這個需求,就可以將button註冊GotFocus和LostFocus就能達到,我們先看看結果圖:

btn

做法是抓取所有的Button,並註冊這兩個事件:

public Form1()
{
    InitializeComponent();
    foreach (var control in this.Controls)
    {
        if (control.GetType() == typeof(Button))
        {
            Button btn = (Button)control;
            btn.GotFocus += btn_GotFocus;
            btn.LostFocus += btn_LostFocus;
        }
    }
}

void btn_LostFocus(object sender, EventArgs e)
{
    //改變該Button的樣式
    Button btn = (Button)sender;
    btn.BackColor = SystemColors.Control;
}

void btn_GotFocus(object sender, EventArgs e)
{
    //改變該Button的樣式
    Button btn = (Button)sender;
    btn.BackColor = System.Drawing.Color.Yellow; //變為黃色
}

參考資料

MSDN

2014年1月27日 星期一

如何使用C#將DataTable轉為自訂物件List<class>

前言

早期.Net開發者習慣使用ADO.NET來時做資料儲存,故像DataReader or DataTable來儲存資料其實還蠻常見的,但這種都屬於弱型別,個人覺得在維護上其實還蠻困難的,故Entity Freamwork出來後改變了很多開發模式,將資料物件化也變成一件很正常的事情,現在在維護舊的WebForm系統,即使使用ADO.NET Fill一個DataTable,我還是會將這些資料轉換成自定義的Class,也許多了一道工,但我覺得差這一點點時間,讓維護上更直覺是很重要的事,畢竟程式不是永遠都你一個人在維護而已阿 ! 故此篇文章將會將實務使用的function來做分享。

實作

自定義的class

image

而這是取得DataTable資料的function,為求Demo而塞一些假資料

image

而實際轉換的function如下,而通常我會新增一個class,讓其他程式能共用

public static class DataTableExtensions
{
public static IList<T> ToList<T>(this DataTable table) where T : new()
{
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
IList<T> result = new List<T>();

//取得DataTable所有的row data
foreach (var row in table.Rows)
{
var item = MappingItem<T>((DataRow)row, properties);
result.Add(item);
}

return result;
}

private static T MappingItem<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
{
T item = new T();
foreach (var property in properties)
{
if (row.Table.Columns.Contains(property.Name))
{
//針對欄位的型態去轉換
if (property.PropertyType == typeof(DateTime))
{
DateTime dt = new DateTime();
if (DateTime.TryParse(row[property.Name].ToString(), out dt))
{
property.SetValue(item, dt, null);
}
else
{
property.SetValue(item, null, null);
}
}
else if (property.PropertyType == typeof(decimal))
{
decimal val = new decimal();
decimal.TryParse(row[property.Name].ToString(), out val);
property.SetValue(item, val, null);
}
else if(property.PropertyType == typeof(double))
{
double val = new double();
double.TryParse(row[property.Name].ToString(), out val);
property.SetValue(item, val, null);
}
else if (property.PropertyType == typeof(int))
{
int val = new int();
int.TryParse(row[property.Name].ToString(), out val);
property.SetValue(item, val, null);
}
else
{
if (row[property.Name] != DBNull.Value)
{
property.SetValue(item, row[property.Name], null);
}
}
}
}
return item;
}
}


使用方式:

List<UserInfo> list = new List<UserInfo>(); 
DataTable dt = GetDataTable();
var result = DataTableExtensions.ToList<UserInfo>(dt).ToList();
list = result.OrderBy(c => c.UpdateDate).ToList();

此.cs檔可至此連結下載 (如有Bug請見諒,或自行擴充~)

2013年12月30日 星期一

KendoUI & ASP.NET MVC系列文章

前言

在ASP.NET WebForm我們有非常多的伺服器控制項,這些控制項減少了Web程式設計師很多工,隨著技術演進,前端技術越來越火紅,越來越多JavaScript函式庫出現(JQuery、knockout.js、Angular.js…),就連UI套件也有JQuery UI、EasyUI、jqGrid等等出現…。開發ASP.NET MVC時,並沒有那些伺服器控制項了,前後端拆分越來越明確,所以開始找尋適合自己的UI FreamWork,後來Study到KendoUI這個套件,開發上還蠻順利的,至於為什麼不用WebForm+KendoUI呢?是因為我覺得Webform本身架構不太適合Ajax,還是用那些伺服器控制項在開發及維護上會好一點(慘痛經驗QQ) !

KendoUI

KendoUI是以Telerik公司推出以JQuery為基礎加上Html5,CSS3的FreamWork,雖然說是HTML5/CSS3,但對於瀏覽器相容器支持度也沒少,且還有針對行動裝置有KendoUI Mobile,因為是以JQuery為基底,對於常使用JQuery開發的我而言,語法都有些親切感,筆者也用過JQuery UI一陣子,但相較之下,我更喜歡KendoUI的配色主題(個人喜好)。就以ASP.NET而言,KendoUI分為Open Source和付費版本,付費版本多了很多MVC的Helper,且享有技術支援,而Open Source授權部分,只要你不把你的網站包成產品販賣,不管是外網使用或公司內部使用都不會有問題,詳細授權的相關問題可看黑暗大的此篇-AJAX式資料清單的新選擇-Kendo UI Grid
image 

文章目的

本系列文章都會使用Open Sorce版本來實做,在Study這個FreamWork的過程,不免有一些學習曲線,希望將這些零散的筆記整理成文章,讓大家選擇這套UI時,能更快上手,當然,過程中使用ASP.NET MVC架構開發,能讓大家(也讓我),做個記錄順便分享開發心得。而最初的幾篇,我將以使用上最頻繁的Grid控制項先講起,未來會陸續增加文章,也會繼續分享其他控制項的開發心得。




系列文章

KendoUI & ASP.NET MVC系列文章 -  在Visual Studio安裝及更換主題
KendoUI & ASP.NET MVC系列文章 -  基本的Grid功能
KendoUI & ASP.NET MVC系列文章 -  處理CRUD-使用Ajax讀取後端Model資料
KendoUI & ASP.NET MVC系列文章 -  處理CRUD-繼續完成新增、修改、刪除
 


2013年12月27日 星期五

KendoUI & ASP.NET MVC系列文章 - 處理CRUD-繼續完成新增、修改、刪除

前言

前一篇我們已經完成利用Ajax來讀取後端資料顯示於Grid,而此篇就會將新增、修改、刪除功能接續完成

CRUD的 Create - 新增

Controller

利用原本樣板產生的程式做一些修改,原本程式如下

image

將上面程式修改為以下,透過MVC的Model Bindder可以接收前端傳來的Customers物件,並依情況回傳是否新增成功

image

View

將dataSrc新增一個Create function,指向後端的CreateCustomer,並在完成後alert處理結果

 image

Schema部分新增model定義,讓KendoUI知道你的模組結構,並且可設定一些欄位驗證

image

接著在屬性部分新增toolbar及editable,editable模式可分為inline(直接在Gird新增一個)或者是popup(彈跳視窗)方式,此例我們希望新增時是跳出一個燈箱視窗

image

結果圖

這樣就完成,在以往我們可能自己要實做View的頁面,現在KendoUI都幫你做好好的,且表單也排得很整理 lol

image


CRUD的Update-編輯

Controller

基本上跟新增大同小異,我們在Controller新增EditCustomer的JsonResult

image 

View

新增一個Update function

image

在columns多一個command成員,並設定edit按鈕(這邊也可以自訂義Button標籤)

image

這樣就完成編輯燈箱視窗了!!

image

CRUD的Delete-刪除

Contoller (這邊就不解釋了)

image

View

image

image

後記

以上是一種實做CRUD的方式,但其實做法有很多種,譬如你也可自訂新增、編輯的View去實做,或者你也可以自訂一些查詢欄位POST到後端去,關於版面,如果要修改中文的顯示其實也可以做到,之後也會分享一些實做心得PO上來。而下一篇,預計完將後端改成用WebAPI + OData的方式實做 =V=

完成程式碼

Contoller

public class GridAjaxController : Controller
{
private NorthwindEntities db = new NorthwindEntities();

// GET: /GridAjax/
public ActionResult Index()
{
return View();
}

public JsonResult GetCustomer(KendoGridRequest request)
{
try
{
var result = db.Customers.ToList();
return Json(new KendoGrid<Customers>(request, result), JsonRequestBehavior.AllowGet);
}
catch (Exception)
{
Dictionary<string, object> error = new Dictionary<string, object>();
error.Add("ErrorCode", -1);
error.Add("ErrorMessage", "讀取資料失敗!");
return Json(error);
}
}

// GET: /GridAjax/Details/5
public ActionResult Details(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Customers customers = db.Customers.Find(id);
if (customers == null)
{
return HttpNotFound();
}
return View(customers);
}

// GET: /GridAjax/Create
public ActionResult Create()
{
return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public JsonResult CreateCustomer(Customers customers)
{
if (ModelState.IsValid)
{
if (TryUpdateModel(customers))
{
db.Customers.Add(customers);
db.SaveChanges();
return Json("新增成功!!");
}
}
return Json("新增失敗!!");
}

public JsonResult EditCustomer(Customers customers)
{
if (ModelState.IsValid)
{
db.Entry(customers).State = EntityState.Modified;
if (TryUpdateModel(customers))
{
db.SaveChanges();
return Json("更新成功!!");
}
}
return Json("更新失敗!!");
}

[AcceptVerbs(HttpVerbs.Post)]
public JsonResult DeleteCustomer(string CustomerID)
{
Customers customers = db.Customers.Find(CustomerID);
db.Customers.Remove(customers);
if (TryUpdateModel(customers))
{
db.SaveChanges();
return Json("刪除成功!!");
}
return Json("刪除失敗!!");
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}

View

@model IEnumerable<KendoUI.Model.Customers>

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/BaseLayoutPage.cshtml";
}

@section scripts
{
<script type="text/javascript">
$(function () {

//資料來源物件改用Ajax
var dataSrc = new kendo.data.DataSource({
transport: {
read: {
type: "POST",
url: "/GridAjax/GetCustomer",
dataType: "json",
complete: function (response, status) {
if (response.responseJSON.ErrorCode == -1) {
alert(response.responseJSON.ErrorMessage);
}
}

},
update: {
url: "/GridAjax/EditCustomer",
dataType: "json",
type: "POST",
complete: function (response, status) {
alert(response.responseJSON);
}
},
create: {
url: "/GridAjax/CreateCustomer",
dataType: "json",
type: "POST",
complete: function (response, status) {
alert(response.responseJSON);
}
},
destroy: {
url: "/GridAjax/DeleteCustomer",
dataType: "json",
type: "POST",
complete: function (response, status) {
alert(response.responseJSON);
}
},
},
schema: {
data: function (d) {
return d.data;
},
total: function (d) { return d.total; },
model: {
id: "CustomerID",
fields: {
product: { editable: false, nullable: false },
CompanyName: { validation: { required: true } },
ContactName: { validation: { required: true } },
City: { validation: { required: true } }
}
}
},
pageSize: 5,
serverPaging: true,
serverSorting: true
});

$("#gridData").kendoGrid({
dataSource: dataSrc,
columns: [
{ field: "CustomerID", title: "CustomerID" },
{ field: "CompanyName", title: "CompanyName" },
{ field: "ContactName", title: "ContactName" },
{ field: "City", title: "City" },
{ command: ["edit","destroy"], title: "&nbsp;", width: "160px" }
], //columns的field對應到customer資料表的欄位
sortable: true,
pageable: true,
filterable: true,
width: 800,
toolbar: ["create"],
editable: {
mode: "popup", //使用Popup的模式編輯資料
update: true, // 若設定為True,當按下Update才server資料
}
});
});
</script>
}
<div id="gridData"></div>


延伸閱讀




2013年12月25日 星期三

KendoUI & ASP.NET MVC系列文章 - 處理CRUD-使用Ajax讀取後端Model資料

前言

前兩篇為KendoUI基本的介紹,而此篇將會使用ASP.NET MVC來實做Ajax讀取資料。以下是本範例的環境:

Visual Studio 2013

ASP.NET MVC 5

Entity Framwork 6.0.2

北風資料庫(localdb)

以上逐一解釋就太佔篇幅了,將會整理一些學習資源於延伸閱讀裡

加入MVC的M (Model)

雖然新增一個MVC專案,就會將Model、View、Contoller三個資料夾拆分好,但實務上,因為Model通常會因為有複雜的關聯表或商業邏輯,所以通常即使是小專案,我還是會將Model變成是一個獨立的專案來處理。

在方案檔點選右鍵→新增專案

image

新增一個KendoUI.Model類別庫

image

在KendoUI.Model專案點右鍵,加入新項目,選擇ADO.NET實體資料模型

image

選擇從資料庫產生(這就是所謂的database first開發方式),而至於北風資料庫如何加到localDB,這邊就不多介紹了

image

選擇建立連線,輸入(localdb)\v11.0,並選擇已建好的資料庫

image

接著加入Customers資料表,本例將已此做Demo

image

接著我們回到Web專案,點選右鍵→加入參考,選擇我們的Model專案,接著整個方案Build一下,讓Web專案看得懂Model專案的class

image

加入MVC的C (Controller )

加入Contoller部分上一篇已經介紹過,而不同的是這次我們選擇自動新增view和基本的Entity Framework model

image

依照下圖,命名為GridAjax,資料來源為北風資料庫的Customers,還有載入上一篇所建置的layout(主要載入一些JQuery和KendoUI函式庫)

image 

新增完後會發現MVC已經幫我們建置好很陽春的Grid了

image 

而我們不需要用此陽春的Gird,再來就是將KendoUI Grid套用進去,我們先回到View,將內建產生的程式碼由以下程式碼替代,KendoUI Grid 的設置方式都不再多說,要注意的是,我們資料來源不再是像前一篇載入一個.js檔,而是用Ajax跟後端要資料。

@model IEnumerable<KendoUI.Model.Customers>

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/BaseLayoutPage.cshtml";
}

@section scripts
{
<script type="text/javascript">
$(function () {
//資料來源物件改用Ajax
var dataSrc = new kendo.data.DataSource({
transport: {
read: {
type: "POST",
url: "/GridAjax/GetCustomer",
dataType: "json"
}
},
pageSize: 20,
serverPaging: true,
serverSorting: true
});

$("#gridData").kendoGrid({
dataSource: dataSrc,
columns: [
{ field: "CustomerID", title: "CustomerID" },
{ field: "CompanyName", title: "CompanyName" },
{ field: "ContactName", title: "ContactName" },
{ field: "City", title: "City" },
], //columns的field對應到customer資料表的欄位
sortable: true,
pageable: true,
filterable: true,
width: '800'
});
});
</script>
}
<div id="gridData"></div>

接著回到Contoller,預設是載入Index時就將Customers資料抓回來


image


但我們希望Grid是用Ajax的方式載入,故做以下小修改,先新增一個接收Ajax的function

private NorthwindEntities db = new NorthwindEntities();

// GET: /GridAjax/
public ActionResult Index()
{
return View();
}

public JsonResult GetCustomer()
{
var customers = db.Customers.ToList();
return Json(customers, JsonRequestBehavior.AllowGet);

}

這樣就很輕鬆的完成Gird繫結資料,但會發現這樣並沒有分頁的功能,所以我們接下來要實做


image


開啟偵錯模式,我們會發現POST過來的資料已有一些分頁的參數(take、skip、page、pagesize、sort),我們可以利用這些參數去進去分頁篩選或排序


image


但是其實不用這麼麻煩…有高手幫我們把這些事情都處理掉了!


首先再方案檔點右鍵,選擇管理Nuget套件,下載安裝KendoGridBinder


image


我們再將Contoller做以下修改,KendoGridRequest和Kendo這個類別就幫我們搞定了分頁排序等等功能

private NorthwindEntities db = new NorthwindEntities();

// GET: /GridAjax/
public ActionResult Index()
{
return View();
}

public JsonResult GetCustomer(KendoGridRequest request)
{
var result = db.Customers.ToList();
return Json(new KendoGrid<Customers>(request, result), JsonRequestBehavior.AllowGet);
}
而View我們增加以下schema的code,至於為什麼要增加此段呢?原因是因為KendoGridBinder這個套件回傳的JSON格式不太相同,他將所有資料放入一個名稱叫data的陣列,和回傳total的數字欄位
    var dataSrc = new kendo.data.DataSource({
transport: {
read: {
type: "POST",
url: "/GridAjax/GetCustomer",
dataType: "json"
}
},
schema: {
data: function (d) {
return d.data;
},
total: function (d) { return d.total; }
},
pageSize: 20,
serverPaging: true,
serverSorting: true
});

image


這樣就輕鬆完成一個多功能的Grid啦!!來看看執行結果吧


1.gif


後記


本篇會有點攏長,但希望用逐步的方式讓初學者能照步驟實做出來,如果對MVC已經相當熟悉的建議可以看黑暗大-在ASP.NET MVC 4中使用Kendo UI Grid 的文章,非常的簡潔明瞭!!


再來的幾篇我們將繼續完成新增、編輯、刪除功能!


延伸閱讀


如果對上列技術不太熟的,建議可以看看這些很棒的文章

mrkt 的程式學習筆記 - ASP.NET MVC 分層架構系列文
天空的垃圾場 – ASP.NET MVC系列文
[下載] 範例資料庫(含中文Northwind資料庫)
LocalDB:微软的新生代轻量级数据库-CSDN.NET
ASP.NET MVC 4 與 jqGrid 入門實作
Kendo UI API Reference