Tutorial: compartir entidades entre varios servicios de dominio
En su aplicación WCF RIA Services, puede que tenga que mostrar datos de una variedad de orígenes de datos o exponer una entidad a más de un servicio de dominio. Por ejemplo, es posible que un sitio web de comercio electrónico tenga que integrar datos de su sistema de procesamiento de pedidos con productos de un servicio de dominio de otro fabricante. RIA Services habilita este escenario admitiendo referencias entre entidades de diferentes tipos de DomainContext. Para obtener más información sobre la naturaleza y las limitaciones de esta característica, vea el tema Entidades compartidas.
En este tutorial, aprenderá dos maneras diferentes de definir una asociación entre entidades en instancias de contexto de dominio diferentes:
En la primera parte, la asociación se define agregando código en el proyecto de servidor.
En la segunda parte, la asociación se define con código en el proyecto de cliente.
Ambos enfoques para definir la asociación utilizan el mismo código en el cliente para recuperar y mostrar los datos.
A efectos ilustrativos en este tutorial, creará dos modelos de entidad y dos servicios de dominio para exponer datos en la base de datos de ejemplo AdventureWorksLT. Normalmente, no crearía dos modelos de entidad y dos servicios de dominio para exponer datos de un origen único. Utilizamos este enfoque aquí para simplificar el ejemplo durante el aprendizaje de la técnica que puede utilizar en escenarios más complicados que emplean varios orígenes de datos. Para obtener otro ejemplo de cómo mostrar datos relacionados de un origen de datos único, vea Tutorial: mostrar datos relacionados en una aplicación de negocios de Silverlight.
Requisitos previos
Este tutorial y los demás tutoriales presentados en la documentación de RIA Services requieren la instalación y configuración correctas de varios programas de requisitos previos, como Visual Studio 2010 y Silverlight Developer Runtime y SDK, además de WCF RIA Services y el Kit de herramientas de WCF RIA Services. También requieren la instalación y configuración de SQL Server 2008 R2 Express con Advanced Services, así como la instalación de las bases de datos OLTP y LT de AdventureWorks.
Los temas del nodo Requisitos previos para WCF RIA Services proporcionan instrucciones detalladas para el cumplimiento de cada uno de estos requisitos previos. Siga las instrucciones proporcionadas en ellos antes de realizar este tutorial para asegurarse de encontrar el menor número de problemas posibles al trabajar en estos tutoriales de RIA Services .
Crear una solución, modelos de datos y servicios de dominio
Para configurar una solución de RIA Services
En Visual Studio 2010, cree un nuevo proyecto de RIA Services seleccionando Archivo, Nuevo y, a continuación, Proyecto.
Aparece el cuadro de diálogo Nuevo proyecto.
Seleccione la plantilla Aplicación de Silverlight en las Plantillas de Silverlight y asigne al nuevo proyecto el nombre SharedEntityExample.
Haga clic en Aceptar.
Aparece el cuadro de diálogo Nueva aplicación de Silverlight.
Active la casilla Habilitar WCF RIA Services situada en la parte inferior de la ventana.
Haga clic en Aceptar para crear la solución.
Para crear dos Entity Data Model
En el Explorador de soluciones, haga clic con el botón secundario en el proyecto de servidor (SharedEntityExample.Web), seleccione Agregar y, a continuación, Nuevo elemento.
Aparece el cuadro de diálogo Agregar nuevo elemento.
Seleccione Datos en la lista de Plantillas instaladas de la izquierda y, a continuación, seleccione la plantilla Entity Data Model de ADO.NET.
Asigne al nuevo archivo el nombre SalesModel.edmx y haga clic en Agregar.
Aparecerá el Asistente para Entity Data Model.
En la pantalla Elegir contenido de Model, seleccione Generar desde la base de datos y, a continuación, haga clic en Siguiente.
En la pantalla Elegir la conexión de datos, cree una conexión de datos a la base de datos AdventureWorksLT.
Si la base de datos AdventureWorksLT no aparece en la lista desplegable, haga clic en Nueva conexión, seleccione el Nombre del servidor correcto y, a continuación, seleccione la base de datos AdventureWorksLT en el menú desplegable del cuadro Conectar con una base de datos situado en la parte inferior de la ventana. Active el botón Probar conexión para asegurarse de que la base de datos esté accesible y haga clic en Aceptar.
Asegúrese de que la casilla Guardar configuración de conexión de entidad en Web.Config como esté activada al volver al Asistente para Entity Data Model y cambie el valor de la configuración de conexión de entidad a Sales_DataEntities.
Haga clic en Siguiente.
En la pantalla Elegir los objetos de base de datos, seleccione la tabla SalesOrderHeader.
Haga clic en Finalizar.
Se crea el modelo de entidad para la tabla.
Repita los pasos anteriores de esta sección para crear otro Entity Data Model para la base de datos AdventureWorksLT, pero asígnele el nombre CustomerModel.edmx, cambie el valor de la configuración de conexión de entidad en Web.config a Customer_DataEntities y seleccione la tabla Customer (SalesLT).
Genere la solución.
Abra el archivo de código para el modelo de entidad Sales y observe que la clase
SalesOrderHeader
tiene una propiedadCustomerID
. Utilizará esta propiedad para asociarSalesOrderHeader
yCustomer
.
Para crear los servicios de dominio
Haga clic con el botón secundario en el proyecto de servidor de SharedEntityExample.Web, seleccione Agregar y Nuevo elemento.
En la lista de categorías, seleccione Web y, a continuación, seleccione la plantilla Clase de servicio de dominio.
Asigne a la clase el nombre SalesDomainService.cs (o SalesDomainService.vb).
Haga clic en Agregar.
Aparece el cuadro de diálogo Agregar nueva clase de servicio de dominio.
Asegúrese de que la casilla Habilitar acceso de cliente esté activada.
En la lista de clases DataContext/ObjectContext disponibles, seleccione el objeto de contexto de datos Sales_DataEntities (Entity Framework).
Sugerencia: Si diera un nombre diferente a su conexión de datos al crear el modelo de la entidad, seleccione el objeto de contexto de datos que contiene la entidad SalesOrderHeader
.En Entidades, active la casilla de la entidad SalesOrderHeader.
Haga clic en Aceptar.
Con ello se genera la clase de servicio de dominio.
Repita los pasos anteriores de esta sección para crear otro servicio de dominio, pero asígnele el nombre CustomerDomainService.cs (o CustomerDomainService.vb), seleccione el objeto de contexto de datos Customer_DataEntities y active la casilla de la entidad Customer.
Genere la solución.
En el proyecto de cliente, en la carpeta Generated_Code, abra el archivo de código generado SharedEntityExample.Web.g.cs (tendrá que mostrar todos para ver este archivo que está oculto de forma predeterminada) y observe que hay un elemento
SalesDomainContext
y un elementoCustomerDomainContext
. Utilizará ambos objetos de contexto de dominio para cargar los datos asociados.Cierre el archivo de código generado.
Definir la asociación con código en el proyecto de servidor
Actualmente tiene dos modelos de entidad independientes y dos servicios de dominio que exponen cada uno una entidad. Puede cargar por separado los datos de cada entidad llamando al servicio de dominio adecuado. Pero para cargar datos que sean una combinación de datos de ambas entidades, debe definir la relación entre estas entidades. Los pasos siguientes muestran cómo definir esa relación en el proyecto de servidor.
Para definir la asociación en el proyecto de servidor
Haga clic con el botón secundario en el proyecto de servidor, seleccione Agregar y, a continuación, Nuevo elemento.
En la lista de categorías, seleccione Web y, a continuación, seleccione la plantilla Clase.
Asigne a la clase el nombre SalesOrderHeader.cs (o SalesOrderHeader.vb) y, a continuación, haga clic en Agregar.
En el archivo de clase
SalesOrderHeader
, agregue la palabra clave partial a la declaración de clase.Partial Public Class SalesOrderHeader End Class
namespace SharedEntityExample.Web { public partial class SalesOrderHeader { } }
Agregue una propiedad denominada
Customer
que devuelva un objeto del tipoCustomer
.Partial Public Class SalesOrderHeader Public Property Customer() As Customer End Class
namespace SharedEntityExample.Web { public partial class SalesOrderHeader { public Customer Customer { get; set; } } }
Agregue una instrucción using (o Imports) para los espacios de nombres System.ComponentModel.DataAnnotations y System.ServiceModel.DomainServices.
Agregue el atributo ExternalReferenceAttribute a la propiedad
Customer
.Agregue el atributo AssociationAttribute a la propiedad
Customer
con los siguientes valores.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; } } }
Genere la solución.
En el proyecto de cliente, en la carpeta Generated_Code, abra el archivo de código generado y observe que la clase
SalesOrderHeader
contiene ahora una propiedadCustomer
con los atributos AssociationAttribute y ExternalReferenceAttribute.Cierre el archivo de código generado.
Cargar los datos de ambas entidades
Las propiedades que hacen referencia a una entidad de otro contexto de dominio serán null hasta que la entidad a que se hace referencia se cargue en su contexto de dominio original. La entidad a que se hace referencia no se carga automáticamente. Debe cargar la entidad a través de su contexto de dominio de origen antes de tener acceso a la entidad a la que se hace referencia cruzada.
Para cargar los datos de ambas entidades
En el proyecto de cliente, abra el archivo MainPage.xaml.
Desde el cuadro de herramientas, arrastre un control DataGrid hasta el interior del elemento Grid.
Se agregan un espacio de nombres XML y referencias a los ensamblados Data.
Asigne a DataGrid el nombre
SalesGrid
y defina las columnas para mostrar los datos combinados tal como se muestra en el código XAML siguiente.<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>
Abra el archivo de código subyacente MainPage.xaml.cs (o MainPage.xaml.vb).
Agregue una instrucción using (o Imports) para el espacio de nombres
SharedEntityExample.Web
y el espacio de nombres System.ServiceModel.DomainServices.Client.Cree variables para las instancias de
SalesDomainContext
yCustomerDomainContext
.Private salesContext As New SalesDomainContext() Private customerContext As New CustomerDomainContext()
private SalesDomainContext salesContext = new SalesDomainContext(); private CustomerDomainContext customerContext = new CustomerDomainContext();
En el constructor, agregue una referencia entre los objetos de contexto de dominio llamando al método AddReference, cargue cada entidad llamando al método Load y establezca las entidades de ventas en el elemento ItemsSource del control DataGrid.
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; } } }
Ejecute la solución.
Verá una instancia de DataGrid que muestra los datos de dos entidades en dos modelos de entidad y servicios de dominio independientes.
Definir la asociación con código en el proyecto de cliente
También puede definir la asociación entre las entidades del cliente sin tener que agregar código al proyecto de servidor. Este enfoque es mejor si, preferiblemente, no introduce una nueva propiedad en el proyecto de servidor cuya única finalidad sea conseguir el objetivo del cliente de mostrar los datos conjuntamente.
Para definir la asociación con código en el proyecto de cliente
En el proyecto de servidor, elimine (o marque como comentario) el archivo SalesOrderHeader.cs (o SalesOrderHeader.vb) completo que agregó anteriormente.
Genere la solución para que el archivo de código generado ya no tenga una propiedad
Customer
en el objetoSalesOrderHeader
.En el proyecto de cliente, agregue un nuevo archivo Class denominado SalesOrderHeader.cs (o SalesOrderHeader.vb).
En el archivo de clase
SalesOrderHeader
, agregue la palabra clave partial a la declaración de clase y cambie el espacio de nombres aSharedEntityExample.Web
. (Si está utilizando Visual Basic, puede especificar el espacio de nombresWeb
utilizando la instrucción Namespace).Esta clase extiende la clase en el archivo de código generado. La clase de entidad generada tiene el espacio de nombres del proyecto de servidor.
Agregue una instrucción using (o Imports para Visual Basic) a los espacios de nombres System.ServiceModel.DomainServices, System.ServiceModel.DomainServices.Client y System.ComponentModel.DataAnnotations.
Para establecer la asociación, defina la propiedad
Customer
o la claseSalesOrderHeader
y márquela con los atributos AssociationAttribute y ExternalReferenceAttribute como se muestra en el siguiente ejemplo de código.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); } } }
Presione F5 para ejecutar la solución.
Ahora debe mostrarse en el explorador la instancia de DataGrid que muestra datos compartidos de cada una de las entidades de los dos modelos de entidad independientes en sus respectivos servicios de dominio.