Procedura: creare un servizio dati utilizzando un'origine dati LINQ to SQL (WCF Data Services)
WCF Data Services espone i dati di entità come servizio dati. Il provider di reflection consente di definire un modello di dati basato su una classe che espone membri che restituiscono un'implementazione di IQueryable. Per essere in grado di apportare aggiornamenti ai dati nell'origine dati, queste classi devono inoltre implementare l'interfaccia IUpdatable. Per ulteriori informazioni, vedere Provider di servizi dati (WCF Data Services). In questo argomento viene illustrato come creare classi LINQ to SQL per l'accesso al database Northwind di esempio tramite il provider di reflection, nonché come creare il servizio dati basato su queste classi di dati.
Per aggiungere classi LINQ to SQL a un progetto
Dal menu Progetto all'interno di un'applicazione Visual Basic o C# scegliere Aggiungi nuovo elemento.
Fare clic sul modello Classi LINQ to SQL.
Modificare il nome in Northwind.dbml.
Scegliere Aggiungi.
Il file Northwind.dbml verrà aggiunto al progetto e verrà visualizzato Progettazione relazionale oggetti.
In Esplora server/database sotto Northwind espandere Tabelle e trascinare la tabella Customers in Progettazione relazionale oggetti.
Verrà creata una classe di entità Customer che verrà visualizzata nell'area di progettazione.
Ripetere il passaggio 6 per le tabelle Orders, Order_Details e Products.
Fare clic con il pulsante destro del mouse sul nuovo file con estensione dbml che rappresenta le classi LINQ to SQL e scegliere Visualizza codice.
Verrà creata una nuova pagina code-behind denominata Northwind.cs contenente una definizione di classe parziale per la classe che eredita dalla classe DataContext, che in questo caso corrisponde a NorthwindDataContext.
Sostituire il contenuto del file di codice Northwind.cs con il codice riportato di seguito. Questo codice implementa il provider di reflection mediante l'estensione di DataContext e delle classi di dati generate da 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 } }
Per creare un servizio dati tramite un modello di dati basato su LINQ to SQL
In Esplora soluzioni fare clic con il pulsante destro del mouse sul nome del progetto ASP.NET, quindi scegliere Aggiungi nuovo elemento.
Nella finestra di dialogo Aggiungi nuovo elemento selezionare WCF Data Service.
Specificare un nome per il servizio, quindi fare clic su OK.
In Visual Studio verranno creati i file del markup XML e del codice per il nuovo servizio. La finestra dell'editor del codice verrà visualizzata per impostazione predefinita.
Nel codice per il servizio dati sostituire il commento
/* TODO: put your data source class name here */
nella definizione della classe che definisce il servizio dati con il tipo del contenitore di entità del modello di dati, che in questo caso corrisponde a NorthwindDataContext.Nel codice per il servizio dati sostituire il codice segnaposto nella funzione
InitializeService
con il codice seguente: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);
In questo modo i client autorizzati saranno in grado di accedere alle risorse per i tre set di entità specificati.
Per testare il servizio dati Northwind.svc tramite un browser, seguire le istruzioni riportate nell'argomento Accesso al servizio da un browser (Guida rapida di WCF Data Services).
Vedere anche
Attività
Procedura: creare un servizio dati utilizzando un'origine dati ADO.NET Entity Framework (WCF Data Services)
Procedura: creare un servizio dati utilizzando il provider di reflection (WCF Data Services)