逐步解說:在多個網域服務中共用實體
您可能需要在 WCF RIA Services 應用程式中顯示來自各種資料來源的資料,或向一個以上的網域服務公開一個實體。例如,電子商務網站可能需要整合來自其訂單處理系統之資料與來自協力廠商網域服務之產品。RIA Services 支援不同 DomainContext 型別的實體之間的參考,因此可適用於這種情況。如需此功能之本質和限制的詳細資訊,請參閱共用的實體主題。
在本逐步解說中,您會看到兩種不同的方法,定義不同網域內容執行個體中實體之間的關聯:
在第一個部分,關聯是透過在伺服器專案中加入程式碼來定義。
在第二個部分,關聯是透過用戶端專案中的程式碼來定義。
定義關聯的這兩種方法會在用戶端上使用相同的程式碼來擷取並顯示資料。
在本逐步解說中,您將建立兩個實體模型和兩個網域服務來公開 AdventureWorksLT 範例資料庫中的資料,供說明之用。您通常不會建立兩個實體模型和兩個網域服務來公開單一來源的資料。我們在此處使用這種方法來簡化範例,同時了解之後可在採用多個資料來源之更複雜情節中使用的技巧。如需顯示單一資料來源之相關資料的其他範例,請參閱逐步解說:顯示 Silverlight 商務應用程式中的相關資料。
必要條件
除了 WCF RIA Services 和 WCF RIA Services 工具組之外,在 RIA Services 文件中呈現的這個逐步解說和其他逐步解說還需要正確安裝並設定數個必要程式 (例如 Visual Studio 2010 和 Silverlight 開發人員執行階段與 SDK)。要執行逐步解說還需要安裝並設定 SQL Server 2008 R2 Express with Advanced Services,以及安裝 AdventureWorks OLTP 和 LT 資料庫。
在 WCF RIA Services 的必要條件節點中的主題也提供符合這些必要條件的詳細指示。請先按照該處提供的指示進行,然後再進行本逐步解說,以確保您在進行本 RIA Services 逐步解說時不會發生問題。
建立方案、資料模型和網域服務
若要設定 RIA Services 方案
在 Visual Studio 2010 中,依序選取 [檔案]、[新增] 和 [專案],來建立新的 RIA Services 專案。
[新增專案] 對話方塊隨即出現。
從 [Silverlight] 範本中選取 [Silverlight 應用程式] 範本,並將新專案命名為 SharedEntityExample。
按一下 [確定]。
[新 Silverlight 應用程式] 對話方塊隨即出現。
選取視窗底部的 [啟用 WCF RIA Services] 核取方塊。
按一下 [確定] 來建立方案。
若要建立兩個實體資料模型
以滑鼠右鍵按一下 [方案總管] 中的伺服器專案 (SharedEntityExample.Web)、選取 [加入],然後選取 [新增項目]。
[加入新項目] 對話方塊隨即出現。
從左側的 [已安裝的範本] 清單中選取 [資料],然後選取 [ADO.NET 實體資料模型] 範本。
將新檔案命名為 SalesModel.edmx,然後按一下 [加入]。
[實體資料模型精靈] 隨即出現。
選取 [選擇模型內容] 畫面中的 [從資料庫產生],然後按 [下一步]。
在 [選擇資料連接] 畫面中,建立 AdventureWorksLT 資料庫的資料連接。
如果 AdventureWorksLT 資料庫沒有出現在下拉式清單中,按一下 [新增連接]、選取正確 [伺服器名稱],然後從視窗下方之 [連接至資料庫] 方塊中的下拉式功能表,選取 [AdventureWorksLT] 資料庫。選取 [測試連接] 按鈕來確定可以存取資料庫,然後按一下 [確定]。
請確認當您返回 [實體資料模型精靈] 時,已選取 [另存 Web.Config 中的實體連接字串為] 核取方塊,然後將實體連接設定的值變更為 Sales_DataEntities。
按一下 [下一步]。
選取 [選擇您的資料庫物件] 畫面中的 [SalesOrderHeader] 資料表。
按一下 [完成]。
資料表的實體模型隨即建立。
重複本節中先前的步驟,建立 AdventureWorksLT 資料庫的另一個實體資料模型,但將其命名為 CustomerModel.edmx、將 Web.config 中的實體連接設定值變更為 Customer_DataEntities,然後選取 [Customer (SalesLT)] 資料表。
建置方案。
開啟 Sales 實體模型的程式碼檔案,並注意
SalesOrderHeader
類別有一個CustomerID
屬性。您將會使用此屬性建立SalesOrderHeader
和Customer
的關聯。
若要建立網域服務
以滑鼠右鍵按一下 SharedEntityExample.Web 伺服器專案,選取 [加入] 和 [新增項目]。
選取類別清單中的 [網頁],然後選取 [DomainService 類別] 範本。
將類別命名為 SalesDomainService.cs (或 SalesDomainService.vb)。
按一下 [加入]。
[加入新的 DomainService 類別] 對話方塊隨即出現。
請確定已選取 [啟用用戶端存取] 核取方塊。
從 [可用的 DataContext/ObjectContext 類別] 清單中選取 [Sales_DataEntities (Entity Framework)] 資料內容物件。
提示: 如果在建立實體模型時為資料連接指定一個不同的名稱,請選取包含 SalesOrderHeader
實體的資料內容物件。選取 [實體] 下的 [SalesOrderHeader] 實體核取方塊。
按一下 [確定]。
這會產生網域服務類別。
重複本節中先前的步驟來建立另一個網域服務,但將其命名為 CustomerDomainService.cs (CustomerDomainService.vb)、選取 [Customer_DataEntities] 資料內容物件,然後選取 [Customer] 實體核取方塊。
建置方案。
在用戶端專案的 Generated_Code 資料夾中,開啟產生的程式碼 SharedEntityExample.Web.g.cs 檔案 (您必須全部顯示,才能看到這個預設為隱藏的檔案),並注意有一個
SalesDomainContext
和一個CustomerDomainContext
。您將使用兩個網域內容物件載入相關聯的資料。關閉產生的程式碼檔案。
定義伺服器專案中與程式碼的關聯
您目前有兩個不同的實體模型及每個都會公開一個實體的兩個網域服務。您可以呼叫適當的網域服務,從任一個實體個別載入資料。但是,若要載入兩個實體之資料組合的資料,您必須定義這些實體之間的關聯性。以下步驟示範如何在伺服器專案中定義該關聯性。
若要在伺服器專案中定義關聯
以滑鼠右鍵按一下伺服器專案,並選取 [加入] 和 [新增項目]。
選取類別清單中的 [網頁],然後選取 [類別] 範本。
將類別命名為 SalesOrderHeader.cs (或 SalesOrderHeader.vb),然後按一下 [加入]。
在
SalesOrderHeader
類別檔案中,將 partial 關鍵字加入至類別宣告。Partial Public Class SalesOrderHeader End Class
namespace SharedEntityExample.Web { public partial class SalesOrderHeader { } }
加入名稱為
Customer
,且傳回Customer
型別之物件的屬性。Partial Public Class SalesOrderHeader Public Property Customer() As Customer End Class
namespace SharedEntityExample.Web { public partial class SalesOrderHeader { public Customer Customer { get; set; } } }
針對 System.ServiceModel.DomainServices 和 System.ComponentModel.DataAnnotations 命名空間,加入 using (或 Imports) 陳述式。
將 ExternalReferenceAttribute 屬性 (Attribute) 加入至
Customer
屬性 (Property)。將 AssociationAttribute 屬性 (Attribute) 加入至具有下列值的
Customer
屬性 (Property)。Imports System.ServiceModel.DomainServices Imports System.ComponentModel.DataAnnotations Partial Public Class SalesOrderHeader <ExternalReference()> _ <Association("Sales_Customer", "CustomerID", "CustomerID")> _ Public Property Customer() As Customer End Class
using System; using System.ServiceModel.DomainServices; using System.ComponentModel.DataAnnotations; namespace SharedEntityExample.Web { public partial class SalesOrderHeader { [ExternalReference] [Association("Sales_Customer", "CustomerID", "CustomerID")] public Customer Customer { get; set; } } }
建置方案。
在用戶端專案的 Generated_Code 資料夾中,開啟產生的程式碼檔案,並注意
SalesOrderHeader
類別現在包含具有 ExternalReferenceAttribute 和 AssociationAttribute 屬性 (Attribute) 的Customer
屬性 (Property)。關閉產生的程式碼檔案。
從兩個實體載入資料
參考來自其他網域內容之實體的屬性將會是 null,直到在其原始網域內容中載入參考的實體為止。系統不會自動載入參考的實體。您必須先存取交互參考的實體,才能夠透過其原始網域內容載入實體。
若要從兩個實體載入資料
開啟用戶端專案中的 MainPage.xaml 檔案。
將 DataGrid 控制項從工具箱拖曳到 Grid 項目中。
XML 命名空間和資料組件的參考隨即加入。
將 DataGrid 命名為
SalesGrid
,然後定義資料行以顯示組合的資料,如以下 XAML 中所示。<UserControl x:Class="SharedEntityExample.MainPage" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <data:DataGrid Name="SalesGrid" AutoGenerateColumns="False"> <data:DataGrid.Columns> <data:DataGridTextColumn Header="Sales Order ID" Binding="{Binding SalesOrderID}"></data:DataGridTextColumn> <data:DataGridTextColumn Header="Total Due" Binding="{Binding TotalDue}"></data:DataGridTextColumn> <data:DataGridTextColumn Header="Order Date" Binding="{Binding OrderDate}"></data:DataGridTextColumn> <data:DataGridTextColumn Header="Customer First Name" Binding="{Binding Customer.FirstName}"></data:DataGridTextColumn> <data:DataGridTextColumn Header="Last Name" Binding="{Binding Customer.LastName}"></data:DataGridTextColumn> </data:DataGrid.Columns> </data:DataGrid> </Grid> </UserControl>
開啟程式碼後置檔案 MainPage.xaml.cs (或 MainPage.xaml.vb)。
針對
SharedEntityExample.Web
命名空間和 System.ServiceModel.DomainServices.Client 命名空間,加入 using (或 Imports) 陳述式。建立
SalesDomainContext
和CustomerDomainContext
執行個體的變數。Private salesContext As New SalesDomainContext() Private customerContext As New CustomerDomainContext()
private SalesDomainContext salesContext = new SalesDomainContext(); private CustomerDomainContext customerContext = new CustomerDomainContext();
在結構函式中呼叫 AddReference 方法來加入網域內容物件之間的參考、呼叫 Load 方法來載入每個實體,然後將銷售實體設為 DataGrid 的 ItemsSource。
Imports SharedEntityExample.Web Imports System.ServiceModel.DomainServices.Client Partial Public Class MainPage Inherits UserControl Private salesContext As New SalesDomainContext() Private customerContext As New CustomerDomainContext() Public Sub New() InitializeComponent() salesContext.AddReference(GetType(Customer), customerContext) Dim salesLoadOp = salesContext.Load(salesContext.GetSalesOrderHeadersQuery()) Dim customerLoadOp = customerContext.Load(customerContext.GetCustomersQuery()) SalesGrid.ItemsSource = salesLoadOp.Entities End Sub End Class
using System; using System.Windows.Controls; using SharedEntityExample.Web; using System.ServiceModel.DomainServices.Client; namespace SharedEntityExample { public partial class MainPage : UserControl { private SalesDomainContext salesContext = new SalesDomainContext(); private CustomerDomainContext customerContext = new CustomerDomainContext(); public MainPage() { InitializeComponent(); salesContext.AddReference(typeof(Customer), customerContext); LoadOperation<SalesOrderHeader> salesLoadOp = salesContext.Load(salesContext.GetSalesOrderHeadersQuery()); LoadOperation<Customer> customerLoadOp = customerContext.Load(customerContext.GetCustomersQuery()); SalesGrid.ItemsSource = salesLoadOp.Entities; } } }
執行方案。
您將會看到一個 DataGrid 執行個體,這個執行個體會將兩個實體中的資料顯示在兩個個別的實體模型和網域服務中。
定義用戶端專案中與程式碼的關聯
您也可以在用戶端上定義實體之間的關聯,而不必將任何程式碼加入至伺服器專案中。如果您不想在伺服器專案中引入新屬性 (其用途僅是為了達成共同顯示資料的用戶端目標),則這個方法比較好。
若要定義用戶端專案中與程式碼的關聯
在伺服器專案中,刪除 (或取消註解) 您先前加入的整個 SalesOrderHeader.cs (或 SalesOrderHeader.vb) 檔案。
建置方案,讓產生的程式碼檔案在
SalesOrderHeader
物件上不再有Customer
屬性。在用戶端專案中,加入名稱為 SalesOrderHeader.cs (或 SalesOrderHeader.vb) 的新類別檔案。
在
SalesOrderHeader
類別檔案中,將 partial 關鍵字加入至類別宣告,然後將命名空間變更為SharedEntityExample.Web
(如果您使用的是 Visual Basic,可以使用 Namespace 陳述式指定Web
命名空間)。此類別會擴充產生之程式碼檔案中的類別。產生的實體類別擁有來自伺服器專案的命名空間。
針對 System.ServiceModel.DomainServices、System.ServiceModel.DomainServices.Client 和 System.ComponentModel.DataAnnotations 命名空間,加入 using (若是 Visual Basic,則為 Imports) 陳述式。
若要建立關聯,請定義
Customer
屬性或SalesOrderHeader
類別,並以 ExternalReferenceAttribute 和 AssociationAttribute 屬性標示,如以下程式碼範例中所示。Imports System.ServiceModel.DomainServices Imports System.ServiceModel.DomainServices.Client Imports System.ComponentModel.DataAnnotations Namespace Web Partial Public Class SalesOrderHeader Private _customer As EntityRef(Of Customer) <ExternalReference()> _ <Association("Sales_Customer", "CustomerID", "CustomerID")> _ Public ReadOnly Property Customer() As Customer Get If (Me._customer Is Nothing) Then Me._customer = New EntityRef(Of Customer)(Me, "Customer", AddressOf Me.FilterCustomer) End If Return Me._customer.Entity End Get End Property Private Function FilterCustomer(ByVal entity As Customer) As Boolean Return (entity.CustomerID = Me.CustomerID) End Function End Class End Namespace
using System; using System.Windows.Controls; using System.ServiceModel.DomainServices; using System.ComponentModel.DataAnnotations; using System.ServiceModel.DomainServices.Client; namespace SharedEntityExample.Web { public partial class SalesOrderHeader { private EntityRef<Customer> _customer; [ExternalReference] [Association("Sales_Customer", "CustomerID", "CustomerID")] public Customer Customer { get { if (this._customer == null) { this._customer = new EntityRef<Customer>(this, "Customer", this.FilterCustomer); } return this._customer.Entity; } } private bool FilterCustomer(Customer entity) { return (entity.CustomerID == this.CustomerID); } } }
若要執行方案,請叫用 F5。
瀏覽器中現在應顯示 DataGrid 執行個體,該執行個體在兩個個別實體模型的對應網域服務中顯示了每個實體共用的資料。