成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用LINQ和ADO.NET創建Silverlight程序

原創
開發 后端
以數據為中心的Web應用程序變得越來越重要,使用Silverlight 2、LINQ和ADO.NET很容易創建富的、以數據為驅動的Web應用程序,本文向你展示創建Silverlight應用程序的基礎知識,如果將其連接到數據源后你的程序會變得更加閃亮。

51CTO.com獨家特稿】在Silverlight中可以創建行業和其它以數據為中心的應用系統,但在Silverlight中處理數據不是一件容易的事情,由于Silverlight包括許多處理數據和支持Web Service及XML的工具,但這些工具僅代表跨過防火墻進行數據訪問的最基礎的部分。

常見的數據訪問策略是使用Web Service和客戶端LINQ共同實現的,如果你正在修改現有Web Service端點強化你的Silverlight應用程序,那么我推薦你使用這個方法。但如果你在使用Silverlight創建一個新的Web Service,就沒有必要這么做了。

對一個典型的Web Service層而言,你在服務器上實現一個傳統的數據訪問策略(自定義業務對象、LINQ to SQL、實體框架、Nhibernate等)通過Web Service暴露數據對象,Web Service僅僅是數據訪問策略下面的網關。

但為了開啟完整的數據連通性,你必須要映射四個數據操作(創建、讀取、更新和刪除)到Web Service方法,下面是一個簡單的支持Product類的service contract,注意我在本文中使用的都是C#。

例1 Product Web Service的Service Contract

[ServiceContract]
public interface ICustomerService
{
  [OperationContract]
  List GetAllProducts();
  [OperationContract]
  Product GetProduct(int productID);
  [OperationContract]
  List GetAllProductsWithCategories();
  [OperationContract]
  Product SaveProduct(Product productToSave);
  [OperationContract]
  void DeleteProduct(Product productToDelete);
}

創建一套服務來處理應用程序完整的數據模型可能是相當費時的,正如這個例子中顯示的,特殊特性的操作可能導致Web Service非常臃腫,換句話說,Web Service將有新的要求和操作要增加,甚至包括不屬于核心業務域的操作。

在例1中你看到GetAllProductsWithCategories操作默認用于檢索Product和分類。即使添加排序、過濾和分頁機制到這個簡單的例子你也不要感到驚訝,如果有一個簡單的方法支持數據操作(如查詢、排序、過濾等)不用每次都手動構建這些機制那將是非常吸引人的,ADO.NET Data Service就正是為此而生的。

ADO.NET Data Service

ADO.NET Data Service的目標是為數據模型提供Web訪問端點,這些端點提供了數據排序、過濾、調整和分頁功能,因此開發人員就不需要在自己去編寫這部分代碼了,實際上,每個端點都是LINQ查詢的起點,就從這個端點上你就可以查詢你想要查找的數據。

但不要認為ADO.NET Data Service是另一個數據訪問策略,實際上,ADO.NET Data Service不執行任何直接的數據訪問操作,它位于數據訪問的上層,圖1顯示了ADO.NET Data Service和它在一個應用程序架構中的位置。

 

圖 1 ADO.NET Data Service層

由于ADO.NET Data Service依賴于數據訪問程序完成真實的數據訪問工作,你必須指定這個方法該如何做,在ADO.NET Data Service中,每個服務(Service)必須回到開啟LINQ的提供程序的后面,實際上,每個端點就是一個Iqueryable端點,因此ADO.NET Data Service支持任何支持Iqueryable的對象。

創建服務(Service)

當你將ADO.NET Data Service添加到你的項目中時,會創建一個新的.svc文件,代表一個服務的類,和Web Service不同,你不需要自己親自實現服務的操作,但要允許DataService類處理這些工作,為了運行這些服務,有兩個小任務必須執行。首先,DataService類需要一個類型參數叫做上下文對象,它是將數據作為服務暴露的類,當你的服務從關系數據庫暴露數據時,這個類是從實體框架(EntityFramework)的ObjectContext或LINQ to SQL的DataContext衍生而來的。

//使用我的NorthwindEntities上下文對象(context object)作為服務(Service)的數據源

public class Products : DataService

上下文對象沒有基數類要求,實際上,你可以創建你自己的上下文對象,只要它的屬性實現了Iqueryable接口,ADO.NET Data Service將會以端點形式暴露這些屬性:

public class StateContext
{
  StateList _states = new StateList();
  public IQueryable States 
  {
    get { return _states.AsQueryable(); } 
  }
}

InitializeService調用中,你可以使用IdataServiceConfiguration對象指定什么類型的許可允許進入服務,ADO.NET Data Service使用名詞和動詞具體指定許可,如例2所示:

例2 設置訪問規則

//這個方法只被調用一次初始化服務端策略
public static void InitializeService(IDataServiceConfiguration config)
{
  //只允許我們讀取和更新Products實體,不允許刪除和創建
  config.SetEntitySetAccessRule("Products", 
                                EntitySetRights.AllRead | 
                                EntitySetRights.WriteUpdate);
  //只允許讀取Category和Suppliers實體
  config.SetEntitySetAccessRule("Categories", EntitySetRights.AllRead);
  config.SetEntitySetAccessRule("Suppliers", EntitySetRights.AllRead);
}

完成這個之后,你可以直接瀏覽服務了,它將會顯示每個端點的原子反饋信息,為了調試ADO.NET Data Service,我建議你禁用Internet Explorer的RSS 反饋視圖,或使用另一個瀏覽器查看服務的XML格式。

#p#

查詢和更新數據

ADO.NET Data Service將服務作為具有代表性的狀態轉換器(Representational State Transfer (REST))暴露,它是一個基礎服務,不是基于SOAP的服務,這意味著要替換掉SOAP封包,服務響應的有效負載只包括數據,不包括原數據(metadata),所有請求都使用HTTP動詞(GET,PUT,POST等)和請求URI描述,假定你有一個如圖2所示的模型描述Products,Categories和Suppliers,ADO.NET Data Service服務將會產生三個端點,每個實體集一個,URI為了確定一個模型中的實體集,只需要使用服務的地址和端點的名字就可以了:http://localhost/{服務名}/{端點名}或http://localhost/Product.svc/Products

圖 2 數據模型示例

URI語法支持許多不同的特性,包括檢索特殊的實體,對結果進行排序、過濾、分頁和調整。

ADO.NET Data Service使用這些URI風格的查詢將數據返回給服務的用戶,目前支持兩個序列化格式(將來的版本很可能會進行擴展):JavaScript對象標記(JavaScript Object Notation即JSON)和基于原子的XML(Atom-based XML)。JSON對于客戶端Web代碼非常有吸引力,而Atom是基于XML的格式,因此需要借助XML解析器。

ADO.NET Data Service在查詢中使用標準的HTTP訪問頭來確定向客戶端返回什么格式,如果你從客戶端(如一個瀏覽器)發出一個請求可以破壞XML,如果你不通過Accept頭指定一個優先選用的格式,默認將使用Atom作為返回的格式。

查詢數據只是解決方案的一部分,我們的最終目標是同時支持查詢和更新,為了支持這些要求,ADO.NET Data Service映射了四個最基本的數據訪問操作到基本的HTTP動詞(如表1所示):

數據訪問動詞 HTTP動詞
Create POST
Read GET
Update PUT
Delete DELETE

表 1 數據訪問動詞 vs HTTP動詞

通過使用這些動詞,ADO.NET Data Service讓服務的用戶可以利用所有的數據操作類型,而不用為不同類型創建專門的端點。使用ADO.NET Data Service更新數據的唯一要求是在數據訪問技術下支持Iupdatable接口,這個接口定義了如何從ADO.NET Data Service更新和傳播到數據源。

Silverlight 2.0客戶端庫

如果你使用ADO.NET Data Service通過URI語法和操作XML來進行查詢和更新數據,你可能會得到你想要的許多功能,但你仍然要自行構建一些管道,ADO.NET Data Service客戶端庫的引入就是要解決這個問題,這個庫允許你直接在Silverlight程序中進行LINQ查詢,由客戶端庫將LINQ查詢翻譯成HTTP查詢或更新請求。

首先,你需要生成一些代碼,這些代碼讀取ADO.NET Data Service服務的元數據,并為服務的實體生成數據類。

為了生成這些代碼,你需要在你的項目(Project)中添加Service Reference,你可以在項目資源管理器(Project Explorer)中Silverlight項目上點擊右鍵,然后選擇‘添加服務引用(即Add Service Reference)’,在彈出的對話框中點擊‘查找(Discover)’按鈕,顯示你項目中的服務(包括ADO.NET Data Service),選擇ADO.NET Data Service端點,點擊確定按鈕。這樣會創建一個新的文件,包含了每個端點對應的data contract類和一個DataServiceContext衍生類,DataServiceContext類用作服務接入點(暴露可查詢的服務端點),這樣會在你的Silverlight項目中包含這些類,并在System.Data.Services.Client.dll(Silverlight 2 SDK的一部分)中添加一個引用。Silverlight客戶端代碼和其它使用.NET的代碼基于LINQ的查詢非常相似,下面是示例代碼:

// 創建服務類指定ADO.NET Data Service的位置
 NorthwindEntities ctx = 
  new NorthwindEntities(new Uri("Products.svc", UriKind.Relative));
//創建LINQ查詢
var qry = from p in ctx.Products
               orderby p.ProductName
                select p;

當你執行這個查詢時,它會直接向目標數據發送一個Web請求,但這里的Silverlight代碼和標準的LINQ查詢不同,在Silverlight中不允許同步Web請求,因此,如果要執行異步,你首先需要將查詢轉換成DataServiceQuery對象,然后再調用BeginExecute啟動異步執行:

// 創建一個DataServiceQuery,因為查詢返回的是Products
DataServiceQuery productQuery =
  (DataServiceQuery)qry;
//指定一個callback函數執行異步查詢
  productQuery.BeginExecute(new 
    AsyncCallback(OnLoadComplete),
    productQuery);

當這些查詢執行完后,無論操作是否成功,在AsyncCallback中指定的方法都會執行,通常你會在AsyncCallback中包含原始查詢,因此可以在callback方法中檢索它,你也可以將其保存為類的一部分,正如你在例3中看到的:

例3 將結果添加到集合中

void OnLoadComplete(IAsyncResult result)
{
  //為查詢獲取一個引用
  DataServiceQuery productQuery =
    (DataServiceQuery)result.AsyncState;
 
  try
  {
    //獲得結果并將其添加到集合中
    List products = productQuery.EndExecute(result).ToList();
 
  }
  catch (Exception ex)
  {
    if (HtmlPage.IsEnabled)
    {
      HtmlPage.Window.Alert("Failed to retrieve data: " + ex.ToString());
    }
  }
 
}

如果你以前還沒有處理過LINQ,理解這些模型可能就非常困難,在寫本文的時候,除了在異步包中執行LINQ(如ThreadPool和BackgroundWorker)外,還沒有關于異步LINQ很好的模型,Silverlight需要所有的請求都是異步的,因此在使用ADO.NET Data Service客戶端庫時需要使用這個模型。

載入相關實體

ADO.NET Data Service也允許你選擇如何載入相關的實體,在前面的例子中,我是從服務器中載入Products(產品)的,每個產品與供應商都有一個關系。使用前面的LINQ查詢,我們只檢索了產品,如果我還想顯示供應商和分類信息,我們可以按需載入相關信息,也可以在原始查詢中明確地從服務器去檢索,這兩種技術各有各的優勢,但如果你清楚地知道需要顯示哪些信息,明確地載入可能更有效,如果你只想為一些實體載入數據,使用按需檢索可能會更好。

默認情況下,如果你沒有明確地載入屬性,關系屬性(如產品供應商)就是空的,為便于按需載入,DataServiceContext類有一個BeginLoadProperty方法(遵循相同的異步模式)可以指定源實體,屬性名和callback。

public void LoadSupplierAsync(Product theProduct)
{
  TheContext.BeginLoadProperty(theProduct,
                               "Supplier",
                               new AsyncCallback(SupplierLoadComplete),
                               null);
  }

  public void SupplierLoadComplete(IAsyncResult result)
  {
    TheContext.EndLoadProperty(result);
  }

調用EndLoadProperty后,屬性和相關的實體就被正確地載入,在許多情況下,你可能想在原始查詢中明確地載入它們,因為如此,LINQ提供者支持Expand擴展方法,這個方法允許你指定屬性的名稱路徑便于查詢執行時載入它們,Expand方法在LINQ查詢的from子句中使用,它告訴提供者視圖載入這些相關實體,例如,如果你使用Expand方法改變了Category 和 Supplier原始查詢,在原始查詢執行期間,我們的對象將會載入這些相關實體:

var qry =
  from p in TheContext.Products.Expand("Supplier").Expand("Category")
          orderby p.ProductName
          select p;

如果你使用ADO.NET Data Service讀取數據,知道如何創建一個查詢,運行它,載入你想要的相關實體。如果你需要真實地修改數據,只需要將你的新數據綁定到你的Silverlight控制器即可。

#p#

變化管理

ADO.NET Data Service客戶端庫不支持對象的自動變更監視,這意味著當對象,集合和關系發生變化時,需要開發人員告訴DataServiceContext這些變化,通知DataServiceContext對象的API相當簡單,如例4所示:

例4 DataServiceContext變更API

方法 描述
AddObject 添加一個新創建的對象
UpdateObject 標記一個已經變化的對象
DeleteObject 標記一個刪除的對象
AddLink 在兩個對象之間添加一個鏈接
UpdateLink 更新兩個對象之間的鏈接
DeleteLink 刪除兩個對象之間的鏈接

這意味著你要監視對象的變化,并在你自己的代碼中通知DataServiceContext對象,表面上看起來這樣讓人很失望,因為沒有實現自動化的變化管理,但這樣可以讓庫變得更有效也更mini。

你可能會對如何監視對象的變化感到奇怪,答案就是生成的代碼中,在每個生成的data contract類中,當類中的數據變化時partial方法被調用,如果這些方法從來沒有使用過,它們本身不會造成任何資源消耗,你可以在任何支持變化通知的data contracts上使用partial方法機制,只需要在partial方法中調用DataServiceContract即可,不用連接DataServiceContract整個類。

幸運的是,Silverlight已經有一個接口支持變化通知了(INotifyPropertyChange),通過這個接口可以在你的實現中將任何變化通知給感興趣的人,例如你可以在你的data contract類(在我們的例子中是Product類)中調用InotifyPropertyChange定義一個事件,當數據發生變化時可以激活它,下面就是具體的示例:

public partial class Product : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;
}

這樣當任何屬性發生變化時都可以觸發一個事件,你可以通過partial方法決定什么時候觸發這個事件,例如,當ProductName發生變化時要通知預定人,只需要調用OnProductNameChanged方法,然后觸發PropertyChanged事件,傳遞ProductName通知變化的屬性給事件預定人,下面是代碼:

partial void OnProductNameChanged()
{
  if (PropertyChanged != null)
  {
    PropertyChanged(this, new PropertyChangedEventArgs("ProductName"));
  } 
}

通過在這些可寫的屬性上調用這些partial方法,監視你對象的變化就很簡單了,當對象發生變化時,你可以注冊PropertyChanged事件然后通知DataServiceContext對象:

//在OnLoadComplete方法中,獲取結果然后將它們添加到集合中
List products = productQuery.EndExecute(result).ToList();
foreach (Product product in products)
{
  //觸發變化通知
  product.PropertyChanged +=
    new PropertyChangedEventHandler(product_PropertyChanged);
}

 

最后你可以調用product_PropertyChanged方法通知DataServiceContext對象:

void product_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
  Product product = (Product)sender;
  TheContext.UpdateObject(product);
}

同樣,在創建對象或刪除對象時也需要通知DataServiceContext,如:

void addNewButton_Click(object sender, RoutedEventArgs e)
{
  Product theProduct = new Product();
  // ...
  TheContext.AddObject(theProduct);
}
 
void deleteButton_Click(object sender, RoutedEventArgs e)
{
  Product theProduct = (Product)theList.SelectItem;
  TheContext.DeleteObject(theProduct);
  theCollection.Remove(theProduct);
}

在這些代碼中,你可以在你的Silverlight UI中修改這些對象,讓數據綁定和變化通知代碼確保讓DataServiceContext知道所有變化都會引發什么后果,但你如何對這些服務執行真實的更新呢?

通過服務更新

現在你的DataServiceContext對象已經知道數據的變化,但還需要一個方法通知給服務器,為了解決這個問題,DataServiceContext類提供了一個BeginSaveChanges方法,它和本文前面描述的查詢都使用了相同的異步方法,BeginSaveChanges方法將所有變化都吸收進DataServiceContext,并將它們發送給服務器:

TheContext.BeginSaveChanges(SaveChangesOptions.None,

new AsyncCallback(OnSaveAllComplete),

null);

調用BeginSaveChanges時,有一個標志枚舉調用SaveChangesOptions,這個枚舉允許你指定兩個選項:是否使用批處理,是否繼續,即使某些變化保存失敗。通常,我建議使用批處理,實際上,在某些父/子關系類型上批處理是必須的,因為父子之間可能使用了引用完整性約束,這樣更新才能保證父子之間的一致性。

保存完畢時,將會執行callback,有兩個機制可以傳播錯誤消息給你,首先,如果在執行保存時出現了異常,當你在調用EndSaveChanges時,會拋出異常,因為如此,你可能想要使用try/catch來捕獲災難性的錯誤;另外,EndSaveChanges返回的類型是一個DataServiceResponse對象,DataServiceResponse有一個HasErrors屬性,但在Silverlight 2 Beta 2版本庫中它還不夠安全:

void OnSaveAllComplete(IAsyncResult result)
{
  bool succeeded = true;
  try
  {
    DataServiceResponse response = 
      (DataServiceResponse)TheContext.EndSaveChanges(result);
 
    foreach (OperationResponse opResponse in response)
    {
      if (opResponse.HasErrors)
      {
        succeeded = false;
      }
    }
 
  }
  catch (Exception ex)
  {
    succeeded = false;
  }
 
  // Alert the User
}

你可以重復使用OperationResponse對象來查看是否出現了錯誤,DataServiceResponse是OperationResponse對象的一個集合,在以后的版本中,你應該可以依賴于DataServiceResponse類自身的HasErrors屬性了。

服務調式

在調試服務時,你要執行三個重要的任務:查看DataServiceContext對象中數據的狀態,查看ADO.NET Data Services產生的請求,以及捕獲服務器錯誤。

首先我們處理DataServiceContext對象中的實體狀態,DataServiceContext類暴露了兩個有用的集合:Entities和Links,這些集合是只讀的,由DataServiceContext進行跟蹤,在調式時,不管你是將對象標記為已變化還是未變化,在調試器中查看這些集合是非常有用的,可以幫助你確定跟蹤思路是不是正確的。

注意對你而言,查看你的Silverlight 2程序對服務器的真實請求也是很重要的,最好的方法是使用網絡代理,我個人使用的是Fiddler2,如果你對Fiddler2不熟悉,也可以使用Web traffic之類的工具來捕獲數據包,查看真正發生了什么。

對于ADO.NET Data Service而言,你可能想查看你在線上傳來傳去的都是什么,即Silverlight程序發出的數據和接收到的數據,可以去我的博客(http://wildermuth.com/2008/06/07/Debugging_ADO_NET_Data_Services_with_Fiddler)轉轉。

最后,.NET Framework 3.5 SP1不會將服務端錯誤傳遞給客戶端了,實際上,服務器上的大部分錯誤都是服務器吞下去的,調試服務端錯誤的最好辦法是在調試菜單(Debug->Exceptions…)中使用Exception選項,配置調試器停止一切.NET異常,如果你選擇了這個選項,你可以通過服務看到拋出的異常。

我在本文的目標是展示ADO.NET Data Service是如何在Silverlight 2和基于服務的模塊之間建立起連接的,現在你應該已經知道如何使用ADO.NET Data Service從服務器讀取數據和往服務器寫數據了,再也不用自己動手設計Web Service了,正如你所看到的,Silverlight、ADO.NET Data Service和LINQ三者的組合讓你可以創建強大的基于數據驅動的Web應用程序,具有Web 2.0技術的所有有點。

 

【編輯推薦】

  1. LINQ to SQL實現數據訪問通用基類
  2. SQL連接中加條件查詢的LINQ表達式寫法
  3. 圖解Silverlight 3的7個新功能
責任編輯:彭凡 來源: 51CTO
相關推薦

2009-09-14 13:37:25

LINQ ADO.NE

2009-08-13 11:22:59

LINQ和ADO.NE

2009-12-29 16:12:25

ADO程序員

2009-12-28 15:11:36

ADO.NET專家

2009-12-25 10:25:59

2009-12-29 14:09:17

ADO.NET通用接口

2009-12-21 17:35:24

ADO.NET對象

2009-12-23 17:30:54

ADO.NET應用程序

2009-11-12 13:26:56

使用ADO.NET參數

2009-12-24 15:18:42

創建ADO.NET

2009-12-24 14:06:22

ADO.NET 應用程

2009-11-13 09:45:54

ADO.NET程序集

2009-12-21 16:45:41

ADO.NET程序

2009-12-25 17:05:32

ADO.NET數據庫

2009-12-22 15:03:51

ADO.NET使用

2011-05-20 17:05:59

ADO.NET

2024-06-18 13:17:02

數據庫框架

2009-12-21 17:23:56

ADO.Net程序

2009-12-24 14:45:32

ADO.NET程序

2009-11-12 10:06:01

ADO.NET讀取數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一区在线视频 | www.亚洲精品 | 日韩精品在线一区 | 羞羞视频网 | 亚洲成人一区二区 | 成人av播放 | 凹凸日日摸日日碰夜夜 | 色视频欧美 | 4h影视 | 国产免费一区二区 | 国产精品18hdxxxⅹ在线 | 成人午夜影院 | 亚洲欧美少妇 | 草草草影院 | www.亚洲一区 | 精品伊人| 国产激情99| 在线免费观看色 | 国产传媒在线播放 | 亚洲国产一区二区三区在线观看 | 国产精品视频在线播放 | 99久久99热这里只有精品 | 午夜激情在线视频 | 国产欧美精品区一区二区三区 | 国产美女永久免费无遮挡 | 亚洲天堂中文字幕 | 久久久视 | 一呦二呦三呦国产精品 | 国产综合在线视频 | 一区二区三区国产精品 | 国产丝袜av | 久久精品这里精品 | 午夜av一区二区 | 精品毛片 | 欧美久久久久久 | 91亚洲国产亚洲国产 | 亚洲福利网站 | 亚洲综合无码一区二区 | 精品国产乱码久久久久久果冻传媒 | 北条麻妃视频在线观看 | 99视频网 |