Cómo: Crear un servicio de datos mediante un origen de datos LINQ to SQL (WCF Data Services)
WCF Data Services expone los datos de entidad como servicio de datos. El proveedor de reflexión le permite definir un modelo de datos que está basado en cualquier clase que exponga miembros que devuelvan una implementación de IQueryable. Para poder realizar actualizaciones en los datos del origen de datos, estas clases también deben implementar la interfaz IUpdatable. Para obtener más información, vea Proveedores de servicios de datos (WCF Data Services). En este tema se muestra cómo crear clases LINQ to SQL que tienen acceso a la base de datos de ejemplo Northwind usando el proveedor de reflexión, así como el modo de crear el servicio de datos que está basado en estas clases de datos.
Para agregar clases LINQ to SQL a un proyecto
En una aplicación de Visual Basic o de C#, en el menú Proyecto, haga clic en Agregar nuevo elemento.
Haga clic en la plantilla Clases de LINQ to SQL.
Cambie el nombre a Northwind.dbml.
Haga clic en Agregar.
Se agrega al proyecto el archivo Northwind.dbml y se abre Object Relational Designer (O/R Designer).
En Servidor/Explorador de bases de datos, bajo Northwind, expanda Tablas y arrastre la tabla Customers a Object Relational Designer (O/R Designer).
Se crea una clase de entidad Customer que aparece en la superficie de diseño.
Repita el paso 6 para las tablas Orders, Order_Details y Products.
Haga clic con el botón secundario en el nuevo archivo .dbml que representa las clases LINQ to SQL y haga clic en Ver código.
Esto crea una nueva página de código subyacente denominada Northwind.cs que contiene una definición de clase parcial para la clase que hereda de la clase DataContext, que en este caso es NorthwindDataContext.
Reemplace el contenido del archivo de código Northwind.cs por el código siguiente. Este código implementa el proveedor de reflexión extendiendo la clase DataContext y las clases de datos generadas por LINQ to SQL:
Imports System.ComponentModel Imports System.Collections Imports System.Linq Imports System.Reflection Imports System.Data.Linq Imports System.Data.Linq.Mapping Imports System.Data.Services Imports System.Data.Services.Common ' Define the key properties for the LINQ to SQL data classes. <DataServiceKeyAttribute("CustomerID")> _ Partial Public Class Customer End Class <DataServiceKeyAttribute("ProductID")> _ Partial Public Class Product End Class <DataServiceKeyAttribute("OrderID")> _ Partial Public Class Order End Class <DataServiceKeyAttribute("OrderID", "ProductID")> _ Partial Public Class Order_Detail End Class #Region "IUpdatable implementation" ' Define the IUpdatable implementation for LINQ to SQL. Partial Public Class NorthwindDataContext Implements IUpdatable ' Creates an object in the container. Function CreateResource(ByVal containerName As String, ByVal fullTypeName As String) _ As Object Implements IUpdatable.CreateResource Dim t = Type.GetType(fullTypeName, True) Dim table = GetTable(t) Dim resource = Activator.CreateInstance(t) table.InsertOnSubmit(resource) Return resource End Function ' Gets the object referenced by the resource. Function GetResource(ByVal query As IQueryable, ByVal fullTypeName As String) As Object _ Implements IUpdatable.GetResource Dim resource = query.Cast(Of Object)().SingleOrDefault() ' fullTypeName can be null for deletes If fullTypeName IsNot Nothing AndAlso resource.GetType().FullName <> fullTypeName Then Throw New ApplicationException("Unexpected type for this resource.") End If Return resource End Function ' Resets the value of the object to its default value. Function ResetResource(ByVal resource As Object) As Object _ Implements IUpdatable.ResetResource Dim t = resource.GetType() Dim table = Mapping.GetTable(t) Dim dummyResource = Activator.CreateInstance(t) For Each member In table.RowType.DataMembers If Not member.IsPrimaryKey AndAlso Not member.IsDeferred AndAlso _ Not member.IsAssociation AndAlso Not member.IsDbGenerated Then Dim defaultValue = member.MemberAccessor.GetBoxedValue(dummyResource) member.MemberAccessor.SetBoxedValue(resource, defaultValue) End If Next Return resource End Function ' Sets the value of the given property on the object. Sub SetValue(ByVal targetResource As Object, ByVal propertyName As String, _ ByVal propertyValue As Object) Implements IUpdatable.SetValue Dim table = Mapping.GetTable(targetResource.GetType()) Dim member = table.RowType.DataMembers.Single(Function(x) x.Name = propertyName) member.MemberAccessor.SetBoxedValue(targetResource, propertyValue) End Sub ' Gets the value of a property on an object. Function GetValue(ByVal targetResource As Object, ByVal propertyName As String) _ As Object Implements IUpdatable.GetValue Dim table = Mapping.GetTable(targetResource.GetType()) Dim member = _ table.RowType.DataMembers.Single(Function(x) x.Name = propertyName) Return member.MemberAccessor.GetBoxedValue(targetResource) End Function ' Sets the related object for a reference. Sub SetReference(ByVal targetResource As Object, ByVal propertyName As String, _ ByVal propertyValue As Object) Implements IUpdatable.SetReference CType(Me, IUpdatable).SetValue(targetResource, propertyName, propertyValue) End Sub ' Adds the object to the related objects collection. Sub AddReferenceToCollection(ByVal targetResource As Object, ByVal propertyName As String, _ ByVal resourceToBeAdded As Object) _ Implements IUpdatable.AddReferenceToCollection Dim pi = targetResource.GetType().GetProperty(propertyName) If pi Is Nothing Then Throw New Exception("Can't find property") End If Dim collection = CType(pi.GetValue(targetResource, Nothing), IList) collection.Add(resourceToBeAdded) End Sub ' Removes the object from the related objects collection. Sub RemoveReferenceFromCollection(ByVal targetResource As Object, ByVal propertyName As String, _ ByVal resourceToBeRemoved As Object) _ Implements IUpdatable.RemoveReferenceFromCollection Dim pi = targetResource.GetType().GetProperty(propertyName) If pi Is Nothing Then Throw New Exception("Can't find property") End If Dim collection = CType(pi.GetValue(targetResource, Nothing), IList) collection.Remove(resourceToBeRemoved) End Sub ' Deletes the resource. Sub DeleteResource(ByVal targetResource As Object) _ Implements IUpdatable.DeleteResource Dim table = GetTable(targetResource.GetType()) table.DeleteOnSubmit(targetResource) End Sub ' Saves all the pending changes. Sub SaveChanges() Implements IUpdatable.SaveChanges SubmitChanges() End Sub ' Returns the actual instance of the resource represented ' by the resource object. Function ResolveResource(ByVal resource As Object) As Object Implements IUpdatable.ResolveResource Return resource End Function ' Reverts all the pending changes. Sub ClearChanges() Implements IUpdatable.ClearChanges ' Raise an exception as there is no real way to do this with LINQ to SQL. ' Comment out the following line if you'd prefer a silent failure Throw New NotSupportedException() End Sub End Class #End Region
using System; using System.ComponentModel; using System.Collections; using System.Linq; using System.Reflection; using System.Data.Linq; using System.Data.Linq.Mapping; using System.Data.Services; using System.Data.Services.Common; namespace NorthwindService { // Define the key properties for the LINQ to SQL data classes. [DataServiceKeyAttribute("CustomerID")] public partial class Customer { } [DataServiceKeyAttribute("ProductID")] public partial class Product { } [DataServiceKeyAttribute("OrderID")] public partial class Order { } [DataServiceKeyAttribute("OrderID", "ProductID")] public partial class Order_Detail { } #region IUpdatable implementation // Define the IUpdatable implementation for LINQ to SQL. public partial class NorthwindDataContext : IUpdatable { // Creates an object in the container. object IUpdatable.CreateResource(string containerName, string fullTypeName) { Type t = Type.GetType(fullTypeName, true); ITable table = GetTable(t); object resource = Activator.CreateInstance(t); table.InsertOnSubmit(resource); return resource; } // Gets the object referenced by the resource. object IUpdatable.GetResource(IQueryable query, string fullTypeName) { object resource = query.Cast<object>().SingleOrDefault(); // fullTypeName can be null for deletes if (fullTypeName != null && resource.GetType().FullName != fullTypeName) throw new ApplicationException("Unexpected type for this resource."); return resource; } // Resets the value of the object to its default value. object IUpdatable.ResetResource(object resource) { Type t = resource.GetType(); MetaTable table = Mapping.GetTable(t); object dummyResource = Activator.CreateInstance(t); foreach (var member in table.RowType.DataMembers) { if (!member.IsPrimaryKey && !member.IsDeferred && !member.IsAssociation && !member.IsDbGenerated) { object defaultValue = member.MemberAccessor.GetBoxedValue(dummyResource); member.MemberAccessor.SetBoxedValue(ref resource, defaultValue); } } return resource; } // Sets the value of the given property on the object. void IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue) { MetaTable table = Mapping.GetTable(targetResource.GetType()); MetaDataMember member = table.RowType.DataMembers.Single(x => x.Name == propertyName); member.MemberAccessor.SetBoxedValue(ref targetResource, propertyValue); } // Gets the value of a property on an object. object IUpdatable.GetValue(object targetResource, string propertyName) { MetaTable table = Mapping.GetTable(targetResource.GetType()); MetaDataMember member = table.RowType.DataMembers.Single(x => x.Name == propertyName); return member.MemberAccessor.GetBoxedValue(targetResource); } // Sets the related object for a reference. void IUpdatable.SetReference( object targetResource, string propertyName, object propertyValue) { ((IUpdatable)this).SetValue(targetResource, propertyName, propertyValue); } // Adds the object to the related objects collection. void IUpdatable.AddReferenceToCollection( object targetResource, string propertyName, object resourceToBeAdded) { PropertyInfo pi = targetResource.GetType().GetProperty(propertyName); if (pi == null) throw new Exception("Can't find property"); IList collection = (IList)pi.GetValue(targetResource, null); collection.Add(resourceToBeAdded); } // Removes the object from the related objects collection. void IUpdatable.RemoveReferenceFromCollection( object targetResource, string propertyName, object resourceToBeRemoved) { PropertyInfo pi = targetResource.GetType().GetProperty(propertyName); if (pi == null) throw new Exception("Can't find property"); IList collection = (IList)pi.GetValue(targetResource, null); collection.Remove(resourceToBeRemoved); } // Deletes the resource. void IUpdatable.DeleteResource(object targetResource) { ITable table = GetTable(targetResource.GetType()); table.DeleteOnSubmit(targetResource); } // Saves all the pending changes. void IUpdatable.SaveChanges() { SubmitChanges(); } // Returns the actual instance of the resource represented // by the resource object. object IUpdatable.ResolveResource(object resource) { return resource; } // Reverts all the pending changes. void IUpdatable.ClearChanges() { // Raise an exception as there is no real way to do this with LINQ to SQL. // Comment out the following line if you'd prefer a silent failure throw new NotSupportedException(); } #endregion } }
Para crear un servicio de datos usando un modelo de datos basado en LINQ to SQL
En el Explorador de soluciones, haga clic con el botón secundario en el nombre del proyecto de ASP.NET y, a continuación, haga clic en Agregar nuevo elemento.
En el cuadro de diálogo Agregar nuevo elemento, seleccione WCF Data Service.
Proporcione un nombre para el servicio y, a continuación, haga clic en Aceptar.
Visual Studio crea los archivos de código y marcado XML para el nuevo servicio. De forma predeterminada, se abre la ventana del editor de código.
En el código para el servicio de datos, reemplace el comentario
/* TODO: put your data source class name here */
de la definición de la clase que define el servicio de datos por el tipo que es el contenedor de entidades del modelo de datos, que en este caso es NorthwindDataContext.En el código del servicio de datos, reemplace el código de marcador de posición de la función
InitializeService
por el siguiente:config.SetEntitySetAccessRule("Customers", EntitySetRights.ReadMultiple) config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead _ Or EntitySetRights.WriteMerge) config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead _ Or EntitySetRights.AllWrite) config.SetEntitySetAccessRule("Products", EntitySetRights.ReadMultiple)
config.SetEntitySetAccessRule("Customers", EntitySetRights.ReadMultiple); config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead | EntitySetRights.WriteMerge); config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead | EntitySetRights.AllWrite); config.SetEntitySetAccessRule("Products", EntitySetRights.ReadMultiple);
Esto permite a los clientes autorizados tener acceso a los recursos para los tres conjuntos de entidades especificados.
Para probar el servicio de datos Northwind.svc usando un explorador web, siga las instrucciones del tema Obtener acceso al servicio desde un explorador web (Tutorial rápido de WCF Data Services).
Vea también
Tareas
Cómo: Crear un servicio de datos mediante un origen de datos de ADO.NET Entity Framework (WCF Data Services)
Cómo: Crear un servicio de datos mediante el proveedor de reflexión (WCF Data Services)