Gewusst wie: Erstellen eines Datendiensts mit einer LINQ to SQL-Datenquelle (WCF Data Services)

WCF Data Services macht Entitätsdaten als Datendienst verfügbar. Der Reflektionsanbieter ermöglicht es Ihnen, ein auf einer Klasse basierendes Datenmodell zu definieren, die Member verfügbar macht, die eine IQueryable-Implementierung zurückgeben. Damit diese Klassen Aktualisierungen an Daten in der Datenquelle vornehmen können, müssen sie auch die IUpdatable-Schnittstelle implementieren. Weitere Informationen finden Sie unter Datendiensteanbieter (WCF Data Services). In diesem Thema wird gezeigt, wie LINQ to SQL-Klassen erstellt werden, die mit dem Reflektionsanbieter auf die Northwind-Beispieldatenbank zugreifen, und wie der Datendienst erstellt wird, der auf diesen Datenklassen basiert.

So fügen Sie einem Projekt LINQ to SQL-Klassen hinzu

  1. Klicken Sie in einer Visual Basic- oder C#-Anwendung im Menü Projekt auf Neues Element hinzufügen.

  2. Klicken Sie auf die Vorlage LINQ to SQL-Klassen.

  3. Ändern Sie den Namen in Northwind.dbml.

  4. Klicken Sie auf Hinzufügen.

    Die Datei Northwind.dbml wird dem Projekt hinzugefügt, und der Object Relational Designer (O/R-Designer) wird geöffnet.

  5. Erweitern Sie in Server/Datenbank-Explorer unter Northwind den Knoten Tabellen, und ziehen Sie die Tabelle Customers auf den Object Relational Designer (O/R-Designer).

    Eine Customer-Entitätsklasse wird erstellt und auf der Entwurfsoberfläche angezeigt.

  6. Wiederholen Sie Schritt 6 für die Tabellen Orders, Order_Details und Products.

  7. Klicken Sie mit der rechten Maustaste auf die neue DBML-Datei, die die LINQ to SQL-Klassen darstellt, und klicken Sie auf Code anzeigen.

    Dadurch wird die neue Code-Behind-Seite Northwind.cs erstellt, die eine partielle Klassendefinition für die Klasse enthält, die von der DataContext-Klasse erbt, in diesem Fall NorthwindDataContext.

  8. Ersetzen Sie den Inhalt der Codedatei Northwind.cs durch folgenden Code. Dieser Code implementiert den Reflektionsanbieter, indem er den DataContext und von LINQ to SQL generierte Datenklassen erweitert:

    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
        }
    }
    

So erstellen Sie einen Datendienst mit einem LINQ to SQL-basierten Datenmodell

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Namen des ASP.NET-Projekts, und klicken Sie dann auf Neues Element hinzufügen.

  2. Wählen Sie im Dialogfeld Neues Element hinzufügen die Option WCF Data Service aus.

  3. Geben Sie einen Namen für den Dienst an, und klicken Sie dann auf OK.

    Visual Studio erstellt das XML-Markup und die Codedateien für den neuen Dienst. In der Standardeinstellung wird das Fenster des Code-Editors geöffnet.

  4. Ersetzen Sie im Code für den Datendienst den Kommentar /* TODO: put your data source class name here */ in der Definition der Klasse, die den Datendienst definiert, durch den Typ, der der Entitätscontainer des Datenmodells ist, in diesem Fall NorthwindDataContext.

  5. Ersetzen Sie im Code für den Datendienst den Platzhaltercode in der InitializeService-Funktion durch Folgendes:

    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);
    

    Dies ermöglicht es berechtigten Clients, auf Ressourcen für die drei angegebenen Entitätenmengen zuzugreifen.

  6. Folgen Sie zum Testen des Northwind.svc-Datendiensts in einem Webbrowser den Anweisungen im Thema Zugreifen auf den Dienst in einem Webbrowser (WCF Data Services-Schnellstart).

Siehe auch

Aufgaben

Gewusst wie Erstellen eines Datendiensts mit einer ADO.NET Entity Framework-Datenquelle (WCF Data Services)
Gewusst wie: Erstellen eines Datendiensts mithilfe des Reflektionsanbieters (WCF Data Services)

Konzepte

Datendiensteanbieter (WCF Data Services)