次の方法で共有


チュートリアル: 複数のドメイン サービス間でのエンティティの共有

WCF RIA サービス アプリケーションでは、さまざまなデータ ソースのデータを表示したり、複数のドメイン サービスに 1 つのエンティティを公開したりすることが必要になる場合があります。たとえば、電子商取引 Web サイトでは、サイトの注文処理システムのデータと、サード パーティのドメイン サービスの製品を統合することが必要になる場合があります。RIA サービス では、さまざまな DomainContext 型のエンティティ間の参照がサポートされているため、このシナリオが可能になります。この機能の特性および制限事項の詳細については、「共有エンティティ」を参照してください。

このチュートリアルでは、異なるドメイン コンテキスト インスタンスのエンティティ間の関連付けを定義する 2 とおりの方法について説明します。

  • 最初の方法では、サーバー プロジェクトにコードを追加して関連付けを定義します。

  • 2 つ目の方法では、クライアント プロジェクトでコードを使用して関連付けを定義します。

関連付けを定義するどちらの方法でも、クライアント側の同じコードを使用してデータを取得および表示します。

このチュートリアルでは、説明を目的として、AdventureWorksLT サンプル データベースのデータを公開するために 2 つのエンティティ モデルと 2 つのドメイン サービスを作成します。通常、1 つのソースのデータを公開するために 2 つのエンティティ モデルと 2 つのドメイン サービスを作成することはありません。ここでは、例を単純にするために、この方法を使用します。この方法は、複数のデータ ソースを利用するより複雑なシナリオで使用できます。1 つのデータ ソースの関連データを表示する別の例については、「チュートリアル: Silverlight ビジネス アプリケーションにおける関連データの表示」を参照してください。

前提条件

このチュートリアル、および RIA サービス のドキュメントで紹介されている他のチュートリアルでは、WCF RIA サービス および WCF RIA サービス Toolkit に加え、Visual Studio 2010 や Silverlight の開発者向けランタイムと SDK など、前提条件となっているいくつかのプログラムが適切にインストールおよび構成されている必要があります。また、SQL Server 2008 R2 Express with Advanced Services をインストールして構成し、AdventureWorks OLTP と LT データベースをインストールすることも必要です。

これらの各前提条件を満たしているかどうかを確認するための詳細な手順については、「WCF RIA Services の前提条件」ノード内のトピックを参照してください。このチュートリアルを進める前に、トピックに記載されている手順に従って、この RIA サービス チュートリアルを実行するときに発生する問題をできるだけ最小限に抑えるようにします。

ソリューション、データ モデル、およびドメイン サービスの作成

RIA Services ソリューションを設定するには

  1. Visual Studio 2010 で、[ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックして、新しい RIA サービス プロジェクトを作成します。

    [新しいプロジェクト] ダイアログ ボックスが表示されます。

  2. [Silverlight] テンプレートの [Silverlight アプリケーション] テンプレートをクリックし、新しいプロジェクトに SharedEntityExample という名前を付けます。

  3. [OK] をクリックします。

    [新しい Silverlight アプリケーション] ダイアログ ボックスが表示されます。

  4. ウィンドウの下部にある [WCF RIA サービスを有効にする] チェック ボックスをオンにします。

  5. [OK] をクリックして、ソリューションを作成します。

2 つのエンティティ データ モデルを作成するには

  1. ソリューション エクスプローラーで、サーバー プロジェクト (SharedEntityExample.Web) を右クリックし、[追加] をポイントして、[新しい項目] をクリックします。

    [新しい項目の追加] ダイアログ ボックスが表示されます。

  2. 左側の [インストールされたテンプレート] の一覧で [データ] をクリックし、[ADO.NET Entity Data Model] テンプレートをクリックします。

  3. 新しいファイルに SalesModel.edmx という名前を付け、[追加] をクリックします。

    Entity Data Model ウィザードが表示されます。

  4. [モデルのコンテンツの選択] 画面で、[データベースから生成] をクリックし、[次へ] をクリックします。

  5. [データ接続の選択] 画面で、AdventureWorksLT データベースへのデータ接続を作成します。

  6. AdventureWorksLT データベースがドロップダウン リストに表示されない場合は、[新しい接続] をクリックし、正しいサーバー名を選択して、ウィンドウの下部にある [データベースへの接続] ボックスの一覧の [AdventureWorksLT] データベースをクリックします。[テスト接続] をクリックしてデータベースにアクセスできることを確認し、[OK] をクリックします。

  7. Entity Data Model ウィザードに戻ったら、[エンティティ接続設定に名前を付けて Web.Config に保存] チェック ボックスがオンになっていることを確認し、エンティティ接続設定の値を Sales_DataEntities に変更します。

  8. [次へ] をクリックします。

  9. [データベース オブジェクトの選択] 画面で、SalesOrderHeader テーブルのチェック ボックスをオンにします。

  10. [完了] をクリックします。

    テーブルのエンティティ モデルが作成されます。

  11. このセクションの前の手順を繰り返して AdventureWorksLT データベースに別の Entity Data Model を作成します。ただし、Entity Data Model に CustomerModel.edmx という名前を付け、Web.config のエンティティ接続設定の値を Customer_DataEntities に変更し、Customer (SalesLT) テーブルのチェック ボックスをオンにします。

  12. ソリューションをビルドします。

  13. Sales エンティティ モデルのコード ファイルを開いて、SalesOrderHeader クラスに CustomerID プロパティがあることを確認します。このプロパティを使用して、SalesOrderHeaderCustomer を関連付けます。

ドメイン サービスを作成するには

  1. SharedEntityExample.Web サーバー プロジェクトを右クリックし、[追加] をポイントして、[新しい項目] をクリックします。

  2. カテゴリの一覧で、[Web] をクリックし、[DomainService クラス] テンプレートをクリックします。

  3. クラスに SalesDomainService.cs (または SalesDomainService.vb) という名前を付けます。

  4. [追加] をクリックします。

    [新しいドメイン サービス クラスの追加] ダイアログ ボックスが表示されます。

  5. [クライアント アクセスを有効にする] チェック ボックスがオンになっていることを確認します。

  6. [使用できる DataContext/ObjectContext クラス] ボックスの一覧の [Sales_DataEntities (Entity Framework)] データ コンテキスト オブジェクトをクリックします。

    Tipヒント :
    エンティティ モデルの作成時にデータ接続に別の名前を指定した場合は、SalesOrderHeader エンティティを含むデータ コンテキスト オブジェクトを選択します。
  7. [エンティティ] で、[SalesOrderHeader] エンティティのチェック ボックスをオンにします。

  8. [OK] をクリックします。

    ドメイン サービス クラスが生成されます。

  9. このセクションの前の手順を繰り返して別のドメイン サービスを作成します。ただし、ドメイン サービスに CustomerDomainService.cs (または CustomerDomainService.vb) という名前を付け、[Customer_DataEntities] データ コンテキスト オブジェクトをクリックし、[Customer] エンティティのチェック ボックスをオンにします。

  10. ソリューションをビルドします。

  11. クライアント プロジェクトで、Generated_Code フォルダーにある SharedEntityExample.Web.g.cs という生成されたコード ファイル (既定で非表示になっているこのファイルを表示するには、すべてのファイルを表示する必要があります) を開いて、SalesDomainContext および CustomerDomainContext があることを確認します。両方のドメイン コンテキスト オブジェクトを使用して、関連付けられたデータを読み込みます。

  12. 生成されたコード ファイルを閉じます。

サーバー プロジェクトでのコードとの関連付けの定義

現在、2 つの個別のエンティティ モデルと、それぞれが 1 つのエンティティを公開する 2 つのドメイン サービスがあります。適切なドメイン サービスを呼び出すことで、どちらのエンティティのデータも個別に読み込むことができます。ただし、両方のエンティティのデータを組み合わせたデータを読み込むには、これらのエンティティ間のリレーションシップを定義する必要があります。サーバー プロジェクトでそのリレーションシップを定義する方法を、次の手順に示します。

サーバー プロジェクトで関連付けを定義するには

  1. サーバー プロジェクトを右クリックし、[追加] をポイントして、[新しい項目] をクリックします。

  2. カテゴリの一覧で、[Web] をクリックし、[クラス] テンプレートをクリックします。

  3. クラスに SalesOrderHeader.cs (または SalesOrderHeader.vb) という名前を付け、[追加] をクリックします。

  4. SalesOrderHeader クラス ファイルで、クラス宣言に partial キーワードを追加します。

    Partial Public Class SalesOrderHeader
    
    End Class
    
    namespace SharedEntityExample.Web
    {
        public partial class SalesOrderHeader
        {
        }
    }
    
  5. 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; }
        }
    }
    
  6. System.ServiceModel.DomainServices 名前空間および System.ComponentModel.DataAnnotations 名前空間の using (または Imports) ステートメントを追加します。

  7. Customer プロパティに ExternalReferenceAttribute 属性を追加します。

  8. 次の値を使用して Customer プロパティに AssociationAttribute 属性を追加します。

    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; }
        }
    }
    
  9. ソリューションをビルドします。

  10. クライアント プロジェクトで、Generated_Code フォルダーにある生成されたコード ファイルを開き、ExternalReferenceAttribute 属性と AssociationAttribute 属性が指定された Customer プロパティが SalesOrderHeader クラスに含まれていることを確認します。

  11. 生成されたコード ファイルを閉じます。

両方のエンティティからのデータの読み込み

別のドメイン コンテキストのエンティティを参照するプロパティは、参照されるエンティティが元のドメイン コンテキストに読み込まれるまで null になります。参照されるエンティティは、自動的に読み込まれません。相互参照するエンティティにアクセスする前に、元のドメイン コンテキストを介してエンティティを読み込む必要があります。

両方のエンティティからデータを読み込むには

  1. クライアント プロジェクトで、MainPage.xaml ファイルを開きます。

  2. ツールボックスから Grid 要素内に DataGrid コントロールをドラッグします。

    XML 名前空間および Data アセンブリへの参照が追加されます。

  3. 次の XAML に示すように、DataGridSalesGrid という名前を付け、組み合わされたデータを表示する列を定義します。

    <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>
    
  4. MainPage.xaml.cs (または MainPage.xaml.vb) という分離コード ファイルを開きます。

  5. SharedEntityExample.Web 名前空間および System.ServiceModel.DomainServices.Client 名前空間の using (または Imports) ステートメントを追加します。

  6. SalesDomainContext および CustomerDomainContext のインスタンスの変数を作成します。

    Private salesContext As New SalesDomainContext()
    Private customerContext As New CustomerDomainContext()
    
    private SalesDomainContext salesContext = new SalesDomainContext();
    private CustomerDomainContext customerContext = new CustomerDomainContext();
    
  7. コンストラクターで、AddReference メソッドを呼び出してドメイン コンテキスト オブジェクト間の参照を追加し、Load メソッドを呼び出して各エンティティを読み込み、DataGridItemsSource に Sales エンティティを設定します。

    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;
            }
        }
    }
    
  8. ソリューションを実行します。

    2 つの個別のエンティティ モデルとドメイン サービスの 2 つのエンティティのデータを表示する DataGrid インスタンスが表示されます。

クライアント プロジェクトでのコードとの関連付けの定義

サーバー プロジェクトにコードを追加せずに、クライアントでエンティティ間の関連付けを定義することもできます。クライアントでデータがまとめて表示されることを唯一の目的とするサーバー プロジェクトに新しいプロパティを追加したくない場合は、この方法をお勧めします。

クライアント プロジェクトでコードとの関連付けを定義するには

  1. サーバー プロジェクトで、以前に追加した SalesOrderHeader.cs (または SalesOrderHeader.vb) ファイル全体を削除 (またはコメントに) します。

  2. ソリューションをビルドします。その結果、生成されたコード ファイルで SalesOrderHeader オブジェクトの Customer プロパティがなくなります。

  3. クライアント プロジェクトで、新しいクラス ファイルに SalesOrderHeader.cs (または SalesOrderHeader.vb) という名前を付けて追加します。

  4. SalesOrderHeader クラス ファイルで、クラス宣言に partial キーワードを追加し、名前空間を SharedEntityExample.Web に変更します (Visual Basic を使用している場合は、Namespace ステートメントを使用して Web 名前空間を指定できます)。

    このクラスは、生成されたコード ファイルでこのクラスを拡張します。生成されたエンティティ クラスには、サーバー プロジェクトの名前空間があります。

  5. System.ServiceModel.DomainServicesSystem.ServiceModel.DomainServices.Client、および System.ComponentModel.DataAnnotations の各名前空間の using (Visual Basic の場合は Imports) ステートメントを追加します。

  6. 次のコード サンプルに示すように、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);
            }
        }
    }
    
  7. F5 キーを押してソリューションを実行します。

    DataGrid インスタンスがブラウザーに表示され、2 つの個別のエンティティ モデルのそれぞれのドメイン サービスの各エンティティで共有されているデータが表示されます。