Share via


DomainContext 和作業

本主題描述 WCF RIA Services 應用程式的用戶端如何使用網域內容與通訊與應用程式中間層的網域服務進行通訊。您不會與用戶端專案中的網域服務直接互動。但是會針對伺服器專案中的每個網域服務,在用戶端專案中產生網域內容類別。您要在網域內容類別上呼叫對應到您要使用之網域服務的方法。產生的網域內容類別衍生自 DomainContext 類別。根據預設,網域內容是以 Context 的後置 (而非用來命名網域服務的 Service 後置) 命名。例如,名稱為 HRService 的網域服務有一個名稱為 HRContext 的對應網域內容。如需定義網域服務方法的詳細資訊,請參閔網域服務

產生的網域內容包含三個建構函式方法:

  1. 內嵌 URI 的預設建構函式,用於透過 HTTP 與網域服務進行通訊。

  2. 可讓您指定替代 URI 的建構函式。

  3. 可讓您提供自訂 DomainClient 實作的建構函式。此建構函式通常用於單元測試,以重新導向至自訂傳輸層。

DomainContext 類別支援查詢、送出以及叫用網域作業。每一種作業類型都有一個表示進行中之非同步作業的對應類別。這些類別包括:LoadOperationSubmitOperationInvokeOperation

EntitySet 物件是在網域內容中,與指出用戶端允許之作業 (插入、更新或刪除) 的屬性一起產生。

查詢

網域內容中的查詢方法通常會有與網域服務查詢方法加上 Query 之後置的相同名稱。例如,網域內容中的 GetCustomersQuery 方法是從網域服務中的 GetCustomers 方法產生。網域內容查詢方法會傳回您可以用來套用其他作業的 EntityQuery 物件。

網域內容中的所有查詢都會以非同步方式執行。若要執行查詢,您要將 EntityQuery 物件當做 Load 方法中的參數傳遞。

如需詳細資訊,請參閱逐步解說:擷取和顯示網域服務的資料

下列程式碼示範如何從網域服務擷取客戶。它會篩選電話號碼開頭為 583 的客戶,然後再依據 LastName 的字母順序排列這些客戶。結果會顯示在 DataGrid 中。

Partial Public Class MainPage
    Inherits UserControl

    Private _customerContext As New CustomerDomainContext

    Public Sub New()
        InitializeComponent()

        Dim query As EntityQuery(Of Customer)

        query = _
            From c In Me._customerContext.GetCustomersQuery() _
            Where c.Phone.StartsWith("583") _
            Order By c.LastName

        Dim loadOp = Me._customerContext.Load(query)
        CustomerGrid.ItemsSource = loadOp.Entities
    End Sub

End Class
public partial class MainPage : UserControl
{
    private CustomerDomainContext _customerContext = new CustomerDomainContext();

    public MainPage()
    {
        InitializeComponent();
        EntityQuery<Customer> query = 
            from c in _customerContext.GetCustomersQuery()
            where c.Phone.StartsWith("583")
            orderby c.LastName
            select c;
        LoadOperation<Customer> loadOp = this._customerContext.Load(query);
        CustomerGrid.ItemsSource = loadOp.Entities;
    }
}

修改資料

當網域服務包含用於更新、插入和刪除實體的方法時,則不會在網域內容中產生那些方法。但是,您使用網域內容上的 SubmitChanges 方法,就會呼叫網域服務上的適當作業。在您呼叫 SubmitChanges 之前,不會在資料來源中進行任何變更。您可以呼叫 RejectChanges 方法來取消暫止的變更。

DomainContext 類別也會提供 HasChangesEntityContainer 屬性,讓您評估暫止的變更。網域內容的 EntityContainer 物件會追蹤暫止的變更。暫止的變更不包含在網域服務中叫用作業的呼叫,因為叫用作業會在呼叫時立即執行。當您呯叫 SubmitChanges 時,所有暫止的變更都會一起傳送到網域服務。

您可以透過呼叫 EntitySet 物件上的 Add 方法,或呼叫 IEditableCollectionView 物件上的 AddNew 方法來加入新實體。當您透過呯叫 AddNew 方法來加入實體時,會先在集合中呈現該物件,然後在資料來源中儲存新的實體。

如需詳細資訊,請參閱逐步解說:編輯網域服務的資料

具名更新方法

網域內容將針對網域服務上的每個具名更新方法,包含一個擁有公用存取修飾詞,而且沒有以 IgnoreAttribute 屬性標示的方法。在網域內容中產生的方法包含與網域服務上的方法相同的名稱。在用戶端專案中,您要呯叫方法,但是在呯叫 SubmitChanges 之前,不會實際執行該方法。EntityContainer 會追蹤具名更新方法的所有呯叫,做為暫止的變更。當您呼叫 SubmitChanges 時,會以非同步方式處理方法。

系統也會針對具名更新方法中當做參數傳遞的實體,在用戶端專案中產生相同的具名更新方法。因此,您可以透過網域內容的執行個體或實體的執行個體來呼叫具名更新方法。如果您開效產生的程式碼檔案,將會注意到網域內容中產生的方法只會呯叫實體中產生的方法。不論是哪一種情況,您都仍然必須呯叫網域內容上的 SubmitChanges 方法,才能執行該方法。

以下範例顯示如何呯叫實體上名稱為 ResetPassword 的具名更新方法。OnSubmitCompleted 是一個回呼方法,實作此方法可處理資料作業的結果。

selectedCustomer.ResetPassword()
customerContext.SubmitChanges(AddressOf OnSubmitCompleted, Nothing)
selectedCustomer.ResetPassword();
customerContext.SubmitChanges(OnSubmitCompleted, null);

叫用作業

網域內容將包含網域服務上,每個叫用作業的方法。不像網域作業,叫用作業會立即執行。您不能呼叫 SubmitChanges 方法。叫用作業是以非同步方式執行。叫用作業會傳回 InvokeOperation 物件。您要擷取 Value 屬性的值,從服務作業取得傳回值。

在絕大多數情況下,您應該使用查詢作業,而不是叫用作業來載入資料。查詢方法會傳回單一 Entity 物件、IQueryable<Entity> 物件或 IEnumerable<Entity> 物件。查詢方法是中介層上的 DomainService 和用戶端上的 DomainContext 所支援資料模式中不可或缺的一部分。RIA Services 架構只會在用戶端專案中針對從 DomainService 中的查詢方法傳回的實體產生實體。

叫用作業提供一個超出範圍的機制來傳回非實體資料,並執行會產生副作用的作業。如需副作用的詳細資訊,請參閱 HasSideEffects 屬性。叫用作業通常不適合查詢方法。即使叫用作業傳回實體,也只有在實體是由查詢方法傳回時,才會針對用戶端專案產生該實體。

下列範例顯示如何使用名稱為 GetLocalTemperature 的叫用作業。在這個範例中,假設方法會擷取與任何實體資料不相關的值。

Dim invokeOp As InvokeOperation(Of Integer)
invokeOp = customerContext.GetLocalTemperature(selectedPostalCode, AddressOf OnInvokeCompleted, Nothing)

Private Sub OnInvokeCompleted(ByVal invOp As InvokeOperation(Of Integer))
  If (invOp.HasError) Then
    MessageBox.Show(String.Format("Method Failed: {0}", invOp.Error.Message))
    invOp.MarkErrorAsHandled()
  Else
    result = invOp.Value
  End If
End Sub
InvokeOperation<int> invokeOp = customerContext.GetLocalTemperature(selectedPostalCode, OnInvokeCompleted, null);

private void OnInvokeCompleted(InvokeOperation<int> invOp)
{
  if (invOp.HasError)
  {
    MessageBox.Show(string.Format("Method Failed: {0}", invOp.Error.Message));
    invOp.MarkErrorAsHandled();
  }
  else
  {
    result = invOp.Value;
  }
}

處理錯誤

當您擷取或修改資料時,您必須決定如何處理從這些作業可能引發的錯誤。當您在網域內容上呼叫擷取或修改資料的方法時,會加入指定處理錯誤之步驟的參數。載入資料時,您可以指定錯誤都會被忽略。修改資料時,您必須處理所傳回的例外狀況。如需詳細資訊,請參閱用戶端上的錯誤處理