- 浏览: 40860 次
文章分类
最新评论
codeplex上不错的文章,转一个
JavaScript 的資料結構處理
只要是寫 Web 應用程式,就一定會碰觸到 JavaScript,而且一定不會只是簡單的幾行指令碼而已,尤其是在小型應用程式(Widget)盛行的今天,想要進入 Web 應用程式領域,不用 JavaScript 老實說就等於不會寫 Web 應用程式一樣,熟悉 JavaScript 可以很容易幫你減少不必要的 server 和 client 之間的 round-trip(往來)流量,也可以早一步先在用戶端做好資訊的整理,再傳回 server 繼續工作,這在很多應用程式都可以看的到它的影子。
通常在 JavaScript 中有幾種處理資料的方法,早期用的最多的就是陣列(Array),後來 JavaScript 陣營發展出特別的一種資料結構組成的方法,稱為 JSON(JavaScript Object Notation),目前也有許多的 JavaScript 函式庫(例如 jQuery)也支援剖析這種類型資料結構的能力,不過不論是一般陣列還是 JSON,都還沒有辦法把解析資料的過程簡化,例如這樣的 JSON 陣列:
[JavaScript]
Samples.People = [
{ ID: 1, FirstName: "Chris", LastName: "Pearson" },
{ ID: 2, FirstName: "Kate", LastName: "Johnson" },
{ ID: 3, FirstName: "Josh", LastName: "Sutherland" },
{ ID: 4, FirstName: "John", LastName: "Ronald" },
{ ID: 5, FirstName: "Steve", LastName: "Pinkerton" },
{ ID: 6, FirstName: "Katie", LastName: "Zimmerman" },
{ ID: 7, FirstName: "Dirk", LastName: "Anderson" },
{ ID: 8, FirstName: "Chris", LastName: "Stevenson" },
{ ID: 9, FirstName: "Bernard", LastName: "Sutherland" },
{ ID: 10, FirstName: "Kate", LastName: "Pinkerton" }
];
一般如果要剖析它的話,必須要解析它的結構,並取回它的每個欄位屬性,在許多 JavaScript 函式庫作者的努力之下,已經可以使用這樣的方法來做:
[JavaScript]
function searchPeople(keywords) {
var found = false;
for (var i = 0; i < People.length; i++) {
if (People[i].FirstName.indexOf(keywords) >= 0) {
alert("Found: " + People[i].FirstName + " " + People[i].LastName);
found = true;
}
}
if (!found)
alert("Not Found.");
}
不過,如果可以像 LINQ 一樣:
[JavaScript]
function searchPeopleWithLinq(keywords) {
var found = false;
JSLINQ(People)
.Where(function(item) {
return (
item.FirstName.indexOf(keywords) >= 0 ||
item.LastName.indexOf(keywords) >= 0);
})
.Select(function(item) {
found = true;
alert("Found: " + item.FirstName + " " + item.LastName);
});
if (!found)
alert("Not Found.");
}
那麼在撰寫以及程式碼的可讀性上會更高一些,這也是本文要介紹的,可以在 JavaScript 中使用類似 LINQ 語法能力的擴充函式庫 JSLINQ。
LINQ on JavaScript
自從 LINQ(語言集合查詢)在 .NET Framework 3.5 中被實現出來以後,受到許多的開發人員青睞,因為它將原本屬於資料庫 SQL 查詢的特性,透過一些由程式語言直接支援的方法,將它實現在撰寫程式的層次上,最終的目的是希望程式人員可以不用學習 SQL 就可以操控資料庫,或是具有集合(Collection)性質的資料,像是陣列或是 List、Dictionary 這類的集合物件,LINQ 可以將原本繁瑣的 foreach 以及條件比對優雅的隱藏起來,並透過像是 Lambda 運算式(Lambda expression)、匿名型別(anonymous types)以及擴充方法(Extended Methods)的語言層次支援,將控制集合資料的方式,呈現的像 SQL 一般的語法,例如:
[C#]
var query = from Student student in arrList
where student.Scores[0] > 95
select student;
foreach (Student s in query)
Console.WriteLine(s.LastName + ": " + s.Scores[0]);
若是有資料庫的支援時(例如 ADO.NET Entity Framework),LINQ 則可以直接查詢資料庫,或是查詢 ADO.NET 的物件(如 DataSet),開發人員不必再去撰寫 ADO.NET 的程式碼,也不用再碰觸到 SQL 指令了。
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Address> addresses = AWEntities.Address;
IQueryable<Address> query =
from address in addresses
where address.AddressLine1.Contains("Algiers Dr.")
select address;
// Addresses on Algiers Dr.
foreach (Address algiersAddress in query)
{
Console.WriteLine("Address 1: " + algiersAddress.AddressLine1);
}
}
這麼好用的工具,目前卻只有 C# 和 VB.NET 能夠享受到,這也未免太不公平了,還好,Chris Pietschmann 幫廣大的 JavaScript 使用族群發展出了一個物件,這個物件可以模擬出 LINQ 的大部份功能,讓 JavaScript 程式也可以享受到 LINQ 的便利之處,就如同上面所揭示的 JavaScript 中的 LINQ 程式一樣。
LINQ to JavaScript 目前可以支援陣列以及 JSON 的處理動作,而且它目前也已經是 jQuery 的外掛套件之一,可以 100% 和 jQuery 核心函式庫相容,將它和 jQuery 一起用會更顯它的靈活性。LINQ to JavaScript 支援下列的運算方法:
投影:Select, SelectMany
條件檢查:Where
排序:OrderBy, OrderByDescending, Reverse
轉換成陣列:ToArray
設定:Distinct, Intersect
數量詞作業:Any, All
串連資料:Concat
彙總:Count
項目作業:First, Last, FirstOrDefault, LastOrDefault, ElementAt, ElementAtOrDefault, DefaultIfEmpty
不過和一般的 LINQ 不太一樣的是,大多數的運算方法都包含一個 clause 參數,這個參數是用來傳回特定條件是否成立(例如 Where)或是處理後續程序(如 Select)所需要的函式指標,就如同在使用 jQuery 的 Callback 函數一樣。有些運算函數有自己的預設行為,但部份是一定要有的,Where 和 Select/SelectMany 運算子就是必須要有的運算函數。
使用方式
LINQ to JavaScript 所需要的核心函式庫在 Codeplex 的網站中可以下載(本文一開始即有網址),將它下載解壓縮後,在 scripts 資料夾中有兩個檔案,一個是 JSLINQ.js,這是核心程式碼,另一個 JSLINQ-vsdoc.js 則是 Intellisense 說明指令碼,若需要使用 Intellisense 時可以使用它。
將 JSLINQ.js 複製到專案中存於 script 指令碼的資料夾,然後在網頁中參照它:
<script type="text/javascript" language="javascript" src="scripts/JSLINQ.js"></script>
接著,使用 JSLINQ 物件將要用在 LINQ 上的資料結構包裝起來,這個資料結構可以是一般陣列或是 JSON 物件:
JSLINQ(array_item);
再使用它的運算子方法,如同使用 LINQ 一樣,不過它的形態比較像是使用函數呼叫用的 LINQ:
JSLINQ(singleArray)
.OrderBy(function(item) { return item; })
.Select(function(item) {
$("span").html($("span").html() + "<br />" + item);
});
上面是可以將陣列的數值排序的 LINQ to JavaScript 指令,完整的 JavaScript 程式碼為:
var singleArray = new Array(0, 2, 3, 6, 65, 30, 430, 654, 23, 103, 49, 97);
function sortArray()
{
JSLINQ(singleArray)
.OrderBy(function(item) { return item; })
.Select(function(item) {
$("span").html($("span").html() + "<br />" + item);
});
}
其執行的結果是:
再來小試一個例子,以相同的陣列,但要過濾出在 50-100 之間的數值,然後用降冪排序(Sort DESC),將上列的 sortArray() 函式修改如下:
var singleArray = new Array(0, 2, 3, 6, 65, 30, 430, 654, 23, 103, 49, 97);
function sortArray()
{
JSLINQ(singleArray)
.Where(function(item) { return (item >= 50 && item <= 100); })
.OrderByDescending(function(item) { return item; })
.Select(function(item) {
$("span").html($("span").html() + "<br />" + item);
});
}
其執行結果如下:
當然,只有這些牛刀小試是滿足不了廣大程式開發人員的胃口的,因為還沒有讓它和 JSON 一起運用,而這個也 JSLINQ 所要處理的問題之一。
實例運用:LINQ to JavaScript with ADO.NET Data Services
ADO.NET Data Service 是一個將資料直接發布在網路上的資料供應服務(Data Provisioning Service),允許用戶端以類似於 SQL 查詢的方式,向服務要求資料,它支援回傳 ATOM(RSS Feed)與 JSON 格式的資料,ATOM 可以用來實作一個定時或不定時更新的 RSS 服務,而 JSON 則可以相容於許多的 JavaScript 應用程式,本文的實例運用就是以這個為主。
Step 1. 建立 ADO.NET Data Services 服務端點(service endpoint)
首先,先建立一個範例資料庫,或是由 Codeplex 上下載 SQL Server 的範例資料庫,筆者所用的是 Northwind 資料庫,並將它附掛在 SQL Server 中(若是使用 SQL Express,則可以用動態掛載的方式來做),然後新增一個 Visual Studio 的網站或是 Web 應用程式專案,並新增一個 ADO.NET 實體資料模型,命名為 Northwind.edmx,並設定存取所有的資料表(不含檢視表與預存程序):
接著建立一個 ADO.NET Data Service,命名為 NorthwindService.svc:
接著開啟NorthwindService.svc.cs 檔案,修改內容如下:
public class NorthwindService : DataService<NorthwindEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}
如此就可以使用 NorthwindService.svc 來存取 Northwind 資料庫中的資料了。
接著,建立一個網頁,可以是 HTML 或 ASP.NET 網頁,然後將下列的內容直接取代現有的網頁內容:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript" src="scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" language="javascript" src="scripts/JSLINQ.js"></script>
<script type="text/javascript" language="javascript">
var categoriesData = null;
$(function() {
$.ajax({
type: "GET",
url: "NorthwindService.svc/Categories",
contentType: "application/json",
data: "{}",
dataType: "json",
success: function(data) {
categoriesData = data.d;
},
error: function(e) {
alert("Error: " + e.description);
}
});
});
function displayCategory(dataItem) {
for (var item in dataItem)
alert("CategoryID: " + dataItem[item].CategoryID +
" Name: " + dataItem[item].CategoryName);
}
function searchCategory() {
JSLINQ(categoriesData)
.Where(function(item) {
return item.CategoryName.indexOf(
$("#txtSearchCategoryKeywords").val()) >= 0;
})
.Select(function(item) {
alert("Found CategoryID: " + item.CategoryID +
" Name: " + item.CategoryName);
});
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
Search Category: <input type="text" id="txtSearchCategoryKeywords" /><input type="button" value="Search" onclick="searchCategory()" />
</div>
</form>
</body>
</html>
這份網頁可以幫助測試 ADO.NET Data Service 是否有正常供應資料,它的畫面是:
請在 Search Category 文字方塊中隨意輸入一行文字,例如 ”Be”,按下 Search,它會呼叫 NorthwindService.svc,並傳回現有的所有 Category 資料回到用戶端(以 JSON 格式),接著使用 LINQ to JavaScript 檢查資料是否存在,若存在則會顯示,否則會顯示 Not Found:
若出現找到的訊息,表示與 ADO.NET Data Service 的服務連線是正常的。
Step 2. 建立客戶搜尋網頁
請在專案中新增一個 Customers.htm(HTML 網頁,不是 Web Form,因為不需要用到 ASP.NET 的東西),並且加入下列的 HTML 碼:
[HTML]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title></title>
<script type="text/javascript" language="javascript"
src="scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" language="javascript" src="scripts/JSLINQ.js"></script>
</head>
<body>
<div class="MainForm" style="width: 100%;">
客戶資料搜尋:<br />
<br />
客戶名稱關鍵字:<input id="txtName" type="text" maxlength="50" /><br />
客戶聯絡人關鍵字:
<input id="txtContactorName" type="text" maxlength="50" /><br />
客戶地址關鍵字:<input id="txtAddress" type="text" maxlength="50" />
<input id="cmdSearch" type="button" value=" 搜尋 "
onclick="searchCustomer()" /><br />
<br />
<div class="DisplayResultGrid" style="width: 900px; ">
<div class="GridHeader; width: 900px">
<div class="Column1" style="width: 150px; float: left;">名稱</div>
<div class="Column2" style="width: 150px; float: left;">聯絡人名稱</div>
<div class="Column3" style="width: 150px; float: left;">地址</div>
<div class="Column4" style="width: 150px; float: left;">電話</div>
<div class="Column5" style="width: 150px; float: left;">傳真</div>
<div class="Column6" style="width: 150px; float: left;">動作</div>
</div>
<div class="GridRows" style="width: 900px; float: left">
</div>
</div>
<div class="GridRowTemplate" style="width: 900px; display: none">
<div class="Column1" style="width: 150px; float: left;"></div>
<div class="Column2" style="width: 150px; float: left;"></div>
<div class="Column3" style="width: 150px; float: left;"></div>
<div class="Column4" style="width: 150px; float: left;"></div>
<div class="Column5" style="width: 150px; float: left;"></div>
<div class="Column6" style="width: 150px; float: left;">
<input class="cmdCalCount" type="button" value=" 訂單數量 " />
<input class="cmdCalAmount" type="button" value=" 訂單總金額 " />
</div>
</div>
</div>
</body>
</html>
網頁執行起來會是這個樣子:
接著,撰寫自 ADO.NET Data Services 中擷取客戶資料的指令碼,依據在前一步驟建立的 NorthwindService.svc,若要取得客戶資料,則可以使用 /Customers 這個 URL 指令,因此我們可以使用下列的指令,在網頁載入時連到 Data Services 以查詢客戶的資料:
var jsonData = null; // 暫存來自 Services 上的客戶 JSON 資料集。
$(function() {
// 連接到 ADO.NET Data Services 取得客戶清單。
$.ajax({
type: "GET",
url: "NorthwindService.svc/Customers",
contentType: "application/json",
data: "{}",
dataType: "json",
success: function(data) {
jsonData = data.d;
},
error: function(e) {
alert("Error: " + e.description);
}
});
});
再來,我們要使用 LINQ to JavaScript 來撰寫客戶搜尋的功能,並將找到的客戶資料列成表格清單,除了要使用到 LINQ 的功能外,還要用到一點 template 以及 jQuery 的函數。基本的 SELECT 的指令是:
[JavaScript]
JSLINQ(jsonData)
.Select(function(item){
// 處理查詢傳回的清單項目。
// item 裝載的即為各個符合條件的物件。
});
加上條件查詢的 SELECT 則是:
[JavaScript]
JSLINQ(jsonData)
.Where(function(item){
// 處理條件的設定,檢查每一項資料是否符合,符合則傳回 true,否則傳回 false。
})
.Select(function(item){
// 處理查詢傳回的清單項目。
// item 裝載的即為各個符合條件的物件。
});
SELECT 也可以支援多重條件查詢,例如:
[JavaScript]
JSLINQ(jsonData)
.Where(function(item){
// 處理條件 1。
})
.Where(function(item){
// 處理條件 2。
})
.Select(function(item){
// 處理查詢傳回的清單項目。
// item 裝載的即為各個符合條件的物件。
});
因此,查詢客戶資料過濾條件的 LINQ 指令,可以寫成如下的方式:
[JavaScript]
function searchCustomer() {
if ($(document.getElementById("txtName")).val() == "" &&
$(document.getElementById("txtContactorName")).val() == "" &&
$(document.getElementById("txtAddress")).val() == "") {
alert("未輸入搜尋條件。");
}
$('div.GridRows').eq(0).empty();
var result =
JSLINQ(jsonData)
.Where(function(item) {
if ($(document.getElementById("txtName")).val() != "")
return item.CompanyName.indexOf(
$(document.getElementById('txtName')).val()) >= 0;
else
return true;
})
.Where(function(item) {
if ($(document.getElementById("txtContactorName")).val() != "")
return item.CompanyName.indexOf(
$(document.getElementById('txtName')).val()) >= 0;
else
return true;
})
.Where(function(item) {
if ($(document.getElementById("txtAddress")).val() != "")
return item.Address.indexOf(
$(document.getElementById('txtAddress')).val()) >= 0;
else
return true;
})
.Select(function(item) {
// 處理結果。
});
}
讀者可以觀察上列的程式碼,使用了多重查詢的條件式,因為範例中使用了三個條件,故使用三個 Where 判斷式來處理,讀者也許會問為何不只用一個就好,當然也可以,但是其條件結果的設定工作就要由讀者自己來處理。
接著,撰寫將結果集填入表格中的指令碼,在本範例中使用 div 物件來組成表格,因此在 HTML 中有一個 <div class=”GridRowTemplate” /> 的 HTML 物件,程式將會使用這個 template 來自動產生每一個資料列,填入資料並且插入列空間區,在這裡使用到 jQuery 的 clone() 以及 append() 函式,以輔助 DOM 上的動作。
// item 是由 Select 傳入的各項符合條件的物件實體。
// 複製 template 並產生新的 jQuery 物件。
var dataRow = $('<div>' + $('div.GridRowTemplate').html() + '</div>').css('display', 'block');
// 填入資料。
dataRow.find('div').eq(0).text(item.CompanyName);
dataRow.find('div').eq(1).text(item.ContactName);
dataRow.find('div').eq(2).text(item.Address);
dataRow.find('div').eq(3).text(item.Phone);
dataRow.find('div').eq(4).text(item.Fax);
// 繫結事件處理常式,下一步會用到。
dataRow.find('div > input.cmdCalCount').bind('click', { id: item.CustomerID }, calculateOrderCount);
dataRow.find('div > input.cmdCalAmount').bind('click', { id: item.CustomerID }, calculateOrderAmount);
// 將資料列設到列空間中。
$('div.GridRows').eq(0).append(dataRow);
dataRow = null;
程式完成後,請執行 Customers.htm,並輸入要檢索的條件,系統會依輸入的關鍵字進行搜尋,並輸出結果,執行結果如下:
Step 3. 查詢客戶的訂單數量及總金額
在前一步生成表格列的指令中,有兩行是設定列中按鈕的事件常式,它們具備查詢客戶在資料庫中的訂單數量以及總金額的能力,但受限於 ADO.NET Data Services 本身的功能,雖然可以查詢訂單數量,但在 Orders Entity 中並沒有 TotalAmount 這一欄位,必須要使用 Order_Details Entity 的 Quantity 以及 UnitPrice 來計算每一項的產品後再加總,再加上無法直接由 Customers 連結到 Order_Details,因此我們需要在 Data Services 中撰寫一個方法來處理這件事。
首先,請開啟 NorthwindService.svc.cs 檔案,並且在裡面加入 GetCustomerOrderItems 方法:
[C#] & [WebGet]
public IQueryable<Order_Details> GetCustomerOrderItems(string CustomerID)
{
var result = from orderDetails in this.CurrentDataSource.Order_Details
join orderInfo in this.CurrentDataSource.Orders
on orderDetails.OrderID equals orderInfo.OrderID
where orderInfo.Customers.CustomerID == CustomerID
select orderDetails;
return result;
}
這個方法所要做的是,將客戶資料所屬的訂單中的明細資料取出並擲回用戶端,所以我們使用了 LINQ to Entities,並配合 join 指令來做聯結,取回訂單的明細資料。
接著,請修改 InitializeService(),加入紅字的項目:
[C#]
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule(
"*", ServiceOperationRights.AllRead);
}
SetServiceOperationAccessRule() 可以設定在 Data Service 服務上每一個(或多個)服務方法的存取權限,由於範例只需要讀取資料,因此設定 AllRead 即可。
接著,請在瀏覽器中使用下列 URL 來測試服務是否正常:
[URL]
http://[你的網站根網址]/
NorthwindService.svc/GetCustomerOrderItems?CustomerID='CHOPS'
若能看到輸出的 ATOM 資料,表示服務可以正常執行:
結語
對於經常撰寫 JavaScript 處理資料的開發人員來說,LINQ to JavaScript 可以協助在集合型或是陣列型資料的處理,尤其是 JSON 的查詢上,它可以幫助過濾以及針對分項的資料做處理,以節省分析結構以及處理內部資料所要花費的時間以及心力。
JavaScript 的資料結構處理
只要是寫 Web 應用程式,就一定會碰觸到 JavaScript,而且一定不會只是簡單的幾行指令碼而已,尤其是在小型應用程式(Widget)盛行的今天,想要進入 Web 應用程式領域,不用 JavaScript 老實說就等於不會寫 Web 應用程式一樣,熟悉 JavaScript 可以很容易幫你減少不必要的 server 和 client 之間的 round-trip(往來)流量,也可以早一步先在用戶端做好資訊的整理,再傳回 server 繼續工作,這在很多應用程式都可以看的到它的影子。
通常在 JavaScript 中有幾種處理資料的方法,早期用的最多的就是陣列(Array),後來 JavaScript 陣營發展出特別的一種資料結構組成的方法,稱為 JSON(JavaScript Object Notation),目前也有許多的 JavaScript 函式庫(例如 jQuery)也支援剖析這種類型資料結構的能力,不過不論是一般陣列還是 JSON,都還沒有辦法把解析資料的過程簡化,例如這樣的 JSON 陣列:
[JavaScript]
Samples.People = [
{ ID: 1, FirstName: "Chris", LastName: "Pearson" },
{ ID: 2, FirstName: "Kate", LastName: "Johnson" },
{ ID: 3, FirstName: "Josh", LastName: "Sutherland" },
{ ID: 4, FirstName: "John", LastName: "Ronald" },
{ ID: 5, FirstName: "Steve", LastName: "Pinkerton" },
{ ID: 6, FirstName: "Katie", LastName: "Zimmerman" },
{ ID: 7, FirstName: "Dirk", LastName: "Anderson" },
{ ID: 8, FirstName: "Chris", LastName: "Stevenson" },
{ ID: 9, FirstName: "Bernard", LastName: "Sutherland" },
{ ID: 10, FirstName: "Kate", LastName: "Pinkerton" }
];
一般如果要剖析它的話,必須要解析它的結構,並取回它的每個欄位屬性,在許多 JavaScript 函式庫作者的努力之下,已經可以使用這樣的方法來做:
[JavaScript]
function searchPeople(keywords) {
var found = false;
for (var i = 0; i < People.length; i++) {
if (People[i].FirstName.indexOf(keywords) >= 0) {
alert("Found: " + People[i].FirstName + " " + People[i].LastName);
found = true;
}
}
if (!found)
alert("Not Found.");
}
不過,如果可以像 LINQ 一樣:
[JavaScript]
function searchPeopleWithLinq(keywords) {
var found = false;
JSLINQ(People)
.Where(function(item) {
return (
item.FirstName.indexOf(keywords) >= 0 ||
item.LastName.indexOf(keywords) >= 0);
})
.Select(function(item) {
found = true;
alert("Found: " + item.FirstName + " " + item.LastName);
});
if (!found)
alert("Not Found.");
}
那麼在撰寫以及程式碼的可讀性上會更高一些,這也是本文要介紹的,可以在 JavaScript 中使用類似 LINQ 語法能力的擴充函式庫 JSLINQ。
LINQ on JavaScript
自從 LINQ(語言集合查詢)在 .NET Framework 3.5 中被實現出來以後,受到許多的開發人員青睞,因為它將原本屬於資料庫 SQL 查詢的特性,透過一些由程式語言直接支援的方法,將它實現在撰寫程式的層次上,最終的目的是希望程式人員可以不用學習 SQL 就可以操控資料庫,或是具有集合(Collection)性質的資料,像是陣列或是 List、Dictionary 這類的集合物件,LINQ 可以將原本繁瑣的 foreach 以及條件比對優雅的隱藏起來,並透過像是 Lambda 運算式(Lambda expression)、匿名型別(anonymous types)以及擴充方法(Extended Methods)的語言層次支援,將控制集合資料的方式,呈現的像 SQL 一般的語法,例如:
[C#]
var query = from Student student in arrList
where student.Scores[0] > 95
select student;
foreach (Student s in query)
Console.WriteLine(s.LastName + ": " + s.Scores[0]);
若是有資料庫的支援時(例如 ADO.NET Entity Framework),LINQ 則可以直接查詢資料庫,或是查詢 ADO.NET 的物件(如 DataSet),開發人員不必再去撰寫 ADO.NET 的程式碼,也不用再碰觸到 SQL 指令了。
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Address> addresses = AWEntities.Address;
IQueryable<Address> query =
from address in addresses
where address.AddressLine1.Contains("Algiers Dr.")
select address;
// Addresses on Algiers Dr.
foreach (Address algiersAddress in query)
{
Console.WriteLine("Address 1: " + algiersAddress.AddressLine1);
}
}
這麼好用的工具,目前卻只有 C# 和 VB.NET 能夠享受到,這也未免太不公平了,還好,Chris Pietschmann 幫廣大的 JavaScript 使用族群發展出了一個物件,這個物件可以模擬出 LINQ 的大部份功能,讓 JavaScript 程式也可以享受到 LINQ 的便利之處,就如同上面所揭示的 JavaScript 中的 LINQ 程式一樣。
LINQ to JavaScript 目前可以支援陣列以及 JSON 的處理動作,而且它目前也已經是 jQuery 的外掛套件之一,可以 100% 和 jQuery 核心函式庫相容,將它和 jQuery 一起用會更顯它的靈活性。LINQ to JavaScript 支援下列的運算方法:
投影:Select, SelectMany
條件檢查:Where
排序:OrderBy, OrderByDescending, Reverse
轉換成陣列:ToArray
設定:Distinct, Intersect
數量詞作業:Any, All
串連資料:Concat
彙總:Count
項目作業:First, Last, FirstOrDefault, LastOrDefault, ElementAt, ElementAtOrDefault, DefaultIfEmpty
不過和一般的 LINQ 不太一樣的是,大多數的運算方法都包含一個 clause 參數,這個參數是用來傳回特定條件是否成立(例如 Where)或是處理後續程序(如 Select)所需要的函式指標,就如同在使用 jQuery 的 Callback 函數一樣。有些運算函數有自己的預設行為,但部份是一定要有的,Where 和 Select/SelectMany 運算子就是必須要有的運算函數。
使用方式
LINQ to JavaScript 所需要的核心函式庫在 Codeplex 的網站中可以下載(本文一開始即有網址),將它下載解壓縮後,在 scripts 資料夾中有兩個檔案,一個是 JSLINQ.js,這是核心程式碼,另一個 JSLINQ-vsdoc.js 則是 Intellisense 說明指令碼,若需要使用 Intellisense 時可以使用它。
將 JSLINQ.js 複製到專案中存於 script 指令碼的資料夾,然後在網頁中參照它:
<script type="text/javascript" language="javascript" src="scripts/JSLINQ.js"></script>
接著,使用 JSLINQ 物件將要用在 LINQ 上的資料結構包裝起來,這個資料結構可以是一般陣列或是 JSON 物件:
JSLINQ(array_item);
再使用它的運算子方法,如同使用 LINQ 一樣,不過它的形態比較像是使用函數呼叫用的 LINQ:
JSLINQ(singleArray)
.OrderBy(function(item) { return item; })
.Select(function(item) {
$("span").html($("span").html() + "<br />" + item);
});
上面是可以將陣列的數值排序的 LINQ to JavaScript 指令,完整的 JavaScript 程式碼為:
var singleArray = new Array(0, 2, 3, 6, 65, 30, 430, 654, 23, 103, 49, 97);
function sortArray()
{
JSLINQ(singleArray)
.OrderBy(function(item) { return item; })
.Select(function(item) {
$("span").html($("span").html() + "<br />" + item);
});
}
其執行的結果是:
再來小試一個例子,以相同的陣列,但要過濾出在 50-100 之間的數值,然後用降冪排序(Sort DESC),將上列的 sortArray() 函式修改如下:
var singleArray = new Array(0, 2, 3, 6, 65, 30, 430, 654, 23, 103, 49, 97);
function sortArray()
{
JSLINQ(singleArray)
.Where(function(item) { return (item >= 50 && item <= 100); })
.OrderByDescending(function(item) { return item; })
.Select(function(item) {
$("span").html($("span").html() + "<br />" + item);
});
}
其執行結果如下:
當然,只有這些牛刀小試是滿足不了廣大程式開發人員的胃口的,因為還沒有讓它和 JSON 一起運用,而這個也 JSLINQ 所要處理的問題之一。
實例運用:LINQ to JavaScript with ADO.NET Data Services
ADO.NET Data Service 是一個將資料直接發布在網路上的資料供應服務(Data Provisioning Service),允許用戶端以類似於 SQL 查詢的方式,向服務要求資料,它支援回傳 ATOM(RSS Feed)與 JSON 格式的資料,ATOM 可以用來實作一個定時或不定時更新的 RSS 服務,而 JSON 則可以相容於許多的 JavaScript 應用程式,本文的實例運用就是以這個為主。
NOTE 本文已假設讀者知道如何使用 Visual Studio 建立 ADO.NET 實體資料模型以及資料服務的方式。若對這方面不了解,請參考 MSDN 中的 ADO.NET Entity Framework 章節的內容,或者參考市面上的 .NET Framework 3.5 相關書籍。
Step 1. 建立 ADO.NET Data Services 服務端點(service endpoint)
首先,先建立一個範例資料庫,或是由 Codeplex 上下載 SQL Server 的範例資料庫,筆者所用的是 Northwind 資料庫,並將它附掛在 SQL Server 中(若是使用 SQL Express,則可以用動態掛載的方式來做),然後新增一個 Visual Studio 的網站或是 Web 應用程式專案,並新增一個 ADO.NET 實體資料模型,命名為 Northwind.edmx,並設定存取所有的資料表(不含檢視表與預存程序):
接著建立一個 ADO.NET Data Service,命名為 NorthwindService.svc:
接著開啟NorthwindService.svc.cs 檔案,修改內容如下:
public class NorthwindService : DataService<NorthwindEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}
如此就可以使用 NorthwindService.svc 來存取 Northwind 資料庫中的資料了。
接著,建立一個網頁,可以是 HTML 或 ASP.NET 網頁,然後將下列的內容直接取代現有的網頁內容:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript" src="scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" language="javascript" src="scripts/JSLINQ.js"></script>
<script type="text/javascript" language="javascript">
var categoriesData = null;
$(function() {
$.ajax({
type: "GET",
url: "NorthwindService.svc/Categories",
contentType: "application/json",
data: "{}",
dataType: "json",
success: function(data) {
categoriesData = data.d;
},
error: function(e) {
alert("Error: " + e.description);
}
});
});
function displayCategory(dataItem) {
for (var item in dataItem)
alert("CategoryID: " + dataItem[item].CategoryID +
" Name: " + dataItem[item].CategoryName);
}
function searchCategory() {
JSLINQ(categoriesData)
.Where(function(item) {
return item.CategoryName.indexOf(
$("#txtSearchCategoryKeywords").val()) >= 0;
})
.Select(function(item) {
alert("Found CategoryID: " + item.CategoryID +
" Name: " + item.CategoryName);
});
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
Search Category: <input type="text" id="txtSearchCategoryKeywords" /><input type="button" value="Search" onclick="searchCategory()" />
</div>
</form>
</body>
</html>
這份網頁可以幫助測試 ADO.NET Data Service 是否有正常供應資料,它的畫面是:
請在 Search Category 文字方塊中隨意輸入一行文字,例如 ”Be”,按下 Search,它會呼叫 NorthwindService.svc,並傳回現有的所有 Category 資料回到用戶端(以 JSON 格式),接著使用 LINQ to JavaScript 檢查資料是否存在,若存在則會顯示,否則會顯示 Not Found:
若出現找到的訊息,表示與 ADO.NET Data Service 的服務連線是正常的。
NOTE 如果讀者對 ADO.NET Data Service 的控制較熟悉的話可以利用它的過濾方式去篩選資料,以減少網路的流量,本文因為要展示 LINQ to JavaScript 的能力,所以未特別處理網路流量的部份。
NOTE 若要要求 ADO.NET Data Service 傳回 JSON 格式的資料,則一定要在要求時使用 application/json 來設定,否則預設都會傳回 ATOM 格式的資料。 [JavaScript] $.ajax({ type: "GET", url: "NorthwindService.svc/Categories", contentType: "application/json", data: "{}", dataType: "json", success: function(data) { categoriesData = data.d; }, error: function(e) { alert("Error: " + e.description); } });
Step 2. 建立客戶搜尋網頁
請在專案中新增一個 Customers.htm(HTML 網頁,不是 Web Form,因為不需要用到 ASP.NET 的東西),並且加入下列的 HTML 碼:
[HTML]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title></title>
<script type="text/javascript" language="javascript"
src="scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" language="javascript" src="scripts/JSLINQ.js"></script>
</head>
<body>
<div class="MainForm" style="width: 100%;">
客戶資料搜尋:<br />
<br />
客戶名稱關鍵字:<input id="txtName" type="text" maxlength="50" /><br />
客戶聯絡人關鍵字:
<input id="txtContactorName" type="text" maxlength="50" /><br />
客戶地址關鍵字:<input id="txtAddress" type="text" maxlength="50" />
<input id="cmdSearch" type="button" value=" 搜尋 "
onclick="searchCustomer()" /><br />
<br />
<div class="DisplayResultGrid" style="width: 900px; ">
<div class="GridHeader; width: 900px">
<div class="Column1" style="width: 150px; float: left;">名稱</div>
<div class="Column2" style="width: 150px; float: left;">聯絡人名稱</div>
<div class="Column3" style="width: 150px; float: left;">地址</div>
<div class="Column4" style="width: 150px; float: left;">電話</div>
<div class="Column5" style="width: 150px; float: left;">傳真</div>
<div class="Column6" style="width: 150px; float: left;">動作</div>
</div>
<div class="GridRows" style="width: 900px; float: left">
</div>
</div>
<div class="GridRowTemplate" style="width: 900px; display: none">
<div class="Column1" style="width: 150px; float: left;"></div>
<div class="Column2" style="width: 150px; float: left;"></div>
<div class="Column3" style="width: 150px; float: left;"></div>
<div class="Column4" style="width: 150px; float: left;"></div>
<div class="Column5" style="width: 150px; float: left;"></div>
<div class="Column6" style="width: 150px; float: left;">
<input class="cmdCalCount" type="button" value=" 訂單數量 " />
<input class="cmdCalAmount" type="button" value=" 訂單總金額 " />
</div>
</div>
</div>
</body>
</html>
網頁執行起來會是這個樣子:
接著,撰寫自 ADO.NET Data Services 中擷取客戶資料的指令碼,依據在前一步驟建立的 NorthwindService.svc,若要取得客戶資料,則可以使用 /Customers 這個 URL 指令,因此我們可以使用下列的指令,在網頁載入時連到 Data Services 以查詢客戶的資料:
var jsonData = null; // 暫存來自 Services 上的客戶 JSON 資料集。
$(function() {
// 連接到 ADO.NET Data Services 取得客戶清單。
$.ajax({
type: "GET",
url: "NorthwindService.svc/Customers",
contentType: "application/json",
data: "{}",
dataType: "json",
success: function(data) {
jsonData = data.d;
},
error: function(e) {
alert("Error: " + e.description);
}
});
});
NOTE 通常在正規環境中,資料量通常不會太小,而且還要看網路傳輸的情況來決定,因此讀者可以試著修改這個函式,加入資料正在載入中的訊息,以提示使用者資料正在載入,這並不是本文的重點,因此筆者就將它留給讀者練習了。
再來,我們要使用 LINQ to JavaScript 來撰寫客戶搜尋的功能,並將找到的客戶資料列成表格清單,除了要使用到 LINQ 的功能外,還要用到一點 template 以及 jQuery 的函數。基本的 SELECT 的指令是:
[JavaScript]
JSLINQ(jsonData)
.Select(function(item){
// 處理查詢傳回的清單項目。
// item 裝載的即為各個符合條件的物件。
});
加上條件查詢的 SELECT 則是:
[JavaScript]
JSLINQ(jsonData)
.Where(function(item){
// 處理條件的設定,檢查每一項資料是否符合,符合則傳回 true,否則傳回 false。
})
.Select(function(item){
// 處理查詢傳回的清單項目。
// item 裝載的即為各個符合條件的物件。
});
SELECT 也可以支援多重條件查詢,例如:
[JavaScript]
JSLINQ(jsonData)
.Where(function(item){
// 處理條件 1。
})
.Where(function(item){
// 處理條件 2。
})
.Select(function(item){
// 處理查詢傳回的清單項目。
// item 裝載的即為各個符合條件的物件。
});
因此,查詢客戶資料過濾條件的 LINQ 指令,可以寫成如下的方式:
[JavaScript]
function searchCustomer() {
if ($(document.getElementById("txtName")).val() == "" &&
$(document.getElementById("txtContactorName")).val() == "" &&
$(document.getElementById("txtAddress")).val() == "") {
alert("未輸入搜尋條件。");
}
$('div.GridRows').eq(0).empty();
var result =
JSLINQ(jsonData)
.Where(function(item) {
if ($(document.getElementById("txtName")).val() != "")
return item.CompanyName.indexOf(
$(document.getElementById('txtName')).val()) >= 0;
else
return true;
})
.Where(function(item) {
if ($(document.getElementById("txtContactorName")).val() != "")
return item.CompanyName.indexOf(
$(document.getElementById('txtName')).val()) >= 0;
else
return true;
})
.Where(function(item) {
if ($(document.getElementById("txtAddress")).val() != "")
return item.Address.indexOf(
$(document.getElementById('txtAddress')).val()) >= 0;
else
return true;
})
.Select(function(item) {
// 處理結果。
});
}
讀者可以觀察上列的程式碼,使用了多重查詢的條件式,因為範例中使用了三個條件,故使用三個 Where 判斷式來處理,讀者也許會問為何不只用一個就好,當然也可以,但是其條件結果的設定工作就要由讀者自己來處理。
接著,撰寫將結果集填入表格中的指令碼,在本範例中使用 div 物件來組成表格,因此在 HTML 中有一個 <div class=”GridRowTemplate” /> 的 HTML 物件,程式將會使用這個 template 來自動產生每一個資料列,填入資料並且插入列空間區,在這裡使用到 jQuery 的 clone() 以及 append() 函式,以輔助 DOM 上的動作。
// item 是由 Select 傳入的各項符合條件的物件實體。
// 複製 template 並產生新的 jQuery 物件。
var dataRow = $('<div>' + $('div.GridRowTemplate').html() + '</div>').css('display', 'block');
// 填入資料。
dataRow.find('div').eq(0).text(item.CompanyName);
dataRow.find('div').eq(1).text(item.ContactName);
dataRow.find('div').eq(2).text(item.Address);
dataRow.find('div').eq(3).text(item.Phone);
dataRow.find('div').eq(4).text(item.Fax);
// 繫結事件處理常式,下一步會用到。
dataRow.find('div > input.cmdCalCount').bind('click', { id: item.CustomerID }, calculateOrderCount);
dataRow.find('div > input.cmdCalAmount').bind('click', { id: item.CustomerID }, calculateOrderAmount);
// 將資料列設到列空間中。
$('div.GridRows').eq(0).append(dataRow);
dataRow = null;
程式完成後,請執行 Customers.htm,並輸入要檢索的條件,系統會依輸入的關鍵字進行搜尋,並輸出結果,執行結果如下:
Step 3. 查詢客戶的訂單數量及總金額
在前一步生成表格列的指令中,有兩行是設定列中按鈕的事件常式,它們具備查詢客戶在資料庫中的訂單數量以及總金額的能力,但受限於 ADO.NET Data Services 本身的功能,雖然可以查詢訂單數量,但在 Orders Entity 中並沒有 TotalAmount 這一欄位,必須要使用 Order_Details Entity 的 Quantity 以及 UnitPrice 來計算每一項的產品後再加總,再加上無法直接由 Customers 連結到 Order_Details,因此我們需要在 Data Services 中撰寫一個方法來處理這件事。
NOTE ADO.NET Data Services 可以支援由開發人員發展自訂的函數以提供在內建的 Entity 無法支援或提供的資料,但此類函數有幾個條件限制,諸如要用 [WebGet]/[WebInvoke] 設定由 Web 存取以外,傳回的資料還必須是 void、IEnumerable<T> 或是 IQueryable<T> 三種型別,否則會無法使用。 這方面的詳細資訊,可參考: http://msdn.microsoft.com/zh-tw/library/cc668788.aspx
首先,請開啟 NorthwindService.svc.cs 檔案,並且在裡面加入 GetCustomerOrderItems 方法:
[C#] & [WebGet]
public IQueryable<Order_Details> GetCustomerOrderItems(string CustomerID)
{
var result = from orderDetails in this.CurrentDataSource.Order_Details
join orderInfo in this.CurrentDataSource.Orders
on orderDetails.OrderID equals orderInfo.OrderID
where orderInfo.Customers.CustomerID == CustomerID
select orderDetails;
return result;
}
這個方法所要做的是,將客戶資料所屬的訂單中的明細資料取出並擲回用戶端,所以我們使用了 LINQ to Entities,並配合 join 指令來做聯結,取回訂單的明細資料。
接著,請修改 InitializeService(),加入紅字的項目:
[C#]
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule(
"*", ServiceOperationRights.AllRead);
}
SetServiceOperationAccessRule() 可以設定在 Data Service 服務上每一個(或多個)服務方法的存取權限,由於範例只需要讀取資料,因此設定 AllRead 即可。
接著,請在瀏覽器中使用下列 URL 來測試服務是否正常:
[URL]
http://[你的網站根網址]/
NorthwindService.svc/GetCustomerOrderItems?CustomerID='CHOPS'
若能看到輸出的 ATOM 資料,表示服務可以正常執行:
結語
對於經常撰寫 JavaScript 處理資料的開發人員來說,LINQ to JavaScript 可以協助在集合型或是陣列型資料的處理,尤其是 JSON 的查詢上,它可以幫助過濾以及針對分項的資料做處理,以節省分析結構以及處理內部資料所要花費的時間以及心力。
MORE INFORMATION Codeplex 上除了LINQ to JavaScript以外,還有幾個類似的函式庫可以用,像是: JSINQ: http://jsinq.codeplex.com/ linq.js: http://linqjs.codeplex.com/ jLINQ: http://jlinq.codeplex.com/ 每個作者對於 LINQ 處理的方式都不太相同,讀者也可以試著去使用它們,來找到真正符合讀者所需的。
相关推荐
而 LINQ to JavaScript (JSLINQ) 是一个独立的开源项目,它将 LINQ 的理念应用到了 JavaScript 语言中,让前端开发人员也能享受到类似的功能,提高代码的可读性和可维护性。 **一、JSLINQ 的基本概念** 1. **查询...
- 分层架构:在分层架构中如何有效地使用LINQ to SQL。 2. **LINQ to XML**: LINQ to XML提供了一种新的处理XML文档的方式,它将XML文档视为对象集合,可以直接进行查询和修改。学习LINQ to XML涉及以下内容: ...
2. **查询表达式**:与LINQ to SQL类似,可以使用C#或VB.NET的查询语法对XML进行复杂查询,如`from el in doc.Descendants("item") select el.Element("title")`。 3. **内存效率**:LINQ to XML在内存使用上更为...
LINQ(Language Integrated Query,语言集成查询)是.NET框架中的一项重要特性,它为C#和Visual Basic等编程语言提供了内置...在实际项目中,结合使用LINQ to SQL和其他.NET框架功能,可以构建出强大且灵活的应用程序。
在传统的XML处理中,我们需要使用DOM(文档对象模型)或XPath、XQuery等来解析和操作XML,而LInq To Xml则将这些操作与C#或VB.NET语言紧密结合,使得XML编程更为高效。 1. **XDocument与XElement**:LInq To Xml的...
此外,LINQ还支持方法链,通过扩展操作符,可以在对象上连续调用方法,形成流畅的API。 本书详细讲解了以下LINQ的核心概念和关键技术: 1. 查询表达式:这是LINQ最直观的部分,使用类似SQL的语法在C#代码中编写...
在提供的"LinqSamples"文件中,可能包含了各种LINQ应用场景的示例代码,如如何使用LINQ to SQL执行数据库查询,如何使用LINQ to DataSet操作数据集,如何使用LINQ to Object处理内存中的数据,以及如何使用LINQ to ...
**Linq技术实例:Linq To Sql与Linq To DataSet** **一、Linq简介** Linq(Language Integrated Query...在实践中,你可以根据提供的"Protice"文件中的内容进一步了解并实践Linq To Sql和Linq To DataSet的各种操作。
【Linq to sql 教程】是一门针对初学者精心设计的教程,旨在帮助学习者逐步掌握使用Linq(Language Integrated Query,语言集成查询)与SQL进行数据操作的技术。Linq是.NET框架中的一个强大特性,它允许开发人员在C#...
Your Complete Example-Rich Guide to Using and Extending LINQ to Objects and PLINQ Using LINQ to Objects, .NET developers can write queries over object collections with the same deep functionality ...
实现linq多个查询条件连接功能(支持linq to sql 和linq to entity)。 按多个指定属性排序功能。 不同参数的lamdba表达式条件间的转换功能。
在这个简单的LINQ to SQL例子中,我们将探讨如何使用C#来实现数据库的基本操作。 首先,我们需要包含必要的命名空间,如`System.Linq`和`System.Data.Linq`,它们提供了 LINQ to SQL 所需的类和方法。接下来,我们...
**Linq之旅:Linq入门详解(实例)** 在.NET框架中,Language ...通过Linq to Objects,我们可以直接在内存中的对象上执行高效、灵活的查询。通过深入学习和实践,你可以充分利用Linq的优势,提高代码的可读性和效率。
LINQ (Language Integrated Query) 是.NET框架中的一种技术,它允许开发者使用类似SQL的查询语法在C#或VB.NET等编程语言中操作对象。...通过理解和实践这些步骤,你可以在你的应用程序中实现高效的分页功能。
LINQ to XML引入了XElement和XAttribute类,用以表示XML元素和属性,使得操作XML就像操作.NET集合一样简单。此外,还会涉及XPath和XQuery的对比,以及如何通过LINQ to XML实现XML文档的转换和验证。 在高级主题部分...
- **.NET Framework 对重定向的支持**:这意味着开发者可以在同一个环境中针对不同版本的 .NET Framework 进行开发。这不仅提高了开发效率,还简化了项目管理。 - **ASP.NET AJAX 和 JavaScript 支持**:ASP.NET ...
理解并熟练使用LINQ to Entities可以帮助开发人员更高效地处理数据库操作,减少与数据库交互的复杂性,提高代码的可读性和可维护性。同时,由于它与Entity Framework紧密集成,可以方便地进行对象-关系映射,实现...
**LINQ to SQL** 是微软.NET Framework中的一种技术,它允许开发者使用C#或VB.NET语言的查询表达式(Language Integrated Query,简称LINQ)直接对SQL数据库进行操作。这项技术将关系数据库的数据操作与对象模型无缝...
- **Linq To Sql动态查询**:Linq To Sql提供了强大的动态查询能力,允许开发者使用对象来构建查询条件,从而避免了SQL字符串拼接的问题,同时也增加了代码的可读性和安全性。 #### 7. Linq To Sql进阶系列(七)...
This is the final part of a three-part series on using LINQ to SQL: Part 1: Mapping Tables to Objects Part 2: Adding/Updating/Deleting Data Part 3: WPF Data Binding with LINQ to SQL These tutorials ...