Freigeben über


Datenmodell (ADO.NET Data Services-Framework)

ADO.NET Data Services bieten systemeigene Unterstützung für ADO.NET Entity Framework-Modelle sowie eine Erweiterung, durch die ein Datenmodell mithilfe von CLR-Objekten (Common Language Runtime) definiert werden kann. Vom ADO.NET Data Services-Framework bereitgestellte Daten werden durch die Terminologie von Entity Data Model (EDM), insbesondere CSDL (Conceptual Schema Definition Language), und Begriffe wie EntitySet, EntityType, Property, Association, AssociationSet usw. beschrieben. Definitionen dieser Begriffe finden Sie unter Begriffe des ADO.NET Data Services-Frameworks. Weitere Informationen zu CSDL finden Sie unter EDM-Spezifikationen.

Durch die Reduzierung von Datenquellen auf eine einzige Grammatik und einheitliche URI-Konventionen können ADO.NET Data Services die Daten unabhängig von der Datenquelle konsistent darstellen. Bei Verwendung eines Entity Framework-Modells ist die Einrichtung eines Datendiensts ohne Bedeutung. Für CLR-basierte Modelle wurde eine Zuordnung zwischen CLR-Objekten und EDM-Typen definiert.

EDM-Datenmodell

In Entity Data Model (EDM) interagieren ADO.NET Data Services mit der Object Services-Ebene von Entity Framework. Dabei handelt es sich um einen CLR-programmierbaren Kontext. Obwohl der Programmierkontext und das konzeptionelle Modell auch manuell erstellt werden können, sollten für diese Aufgabe die in Microsoft Visual Studio 2008 ab SP1 integrierten Entity Data Model-Tools verwendet werden.

Ein Beispiel für die Verwendung von EDM und der Entity Framework-Tools finden Sie unter Schnellstart von Datendiensten (ADO.NET Data Services-Framework).

CLR-basiertes Datenmodell

ADO.NET Data Services konvertieren URI-Anforderungen in Vorgänge für die Daten, die durch die URI-Syntax adressiert werden. Wenn das Datenmodell auf Entity Framework basiert, werden URIs in Object Services-Methodenaufrufe konvertiert. Vom ObjectContext von Entity Framework werden Datensätze anhand einer ObjectQuery<T> bereitgestellt, und ObjectQuery<T> implementiert IQueryable<T>.

Alle Technologien oder Datenanbieter, die Daten durch Implementieren einer Ableitung von IQueryable bereitstellen, können als ADO.NET-Datendienst bereitgestellt werden. Die AsQueryable-Erweiterungsmethode, die ab .NET Framework 3.5 verfügbar ist, kann mit Objekten verwendet werden, die IEnumerable<T> implementieren. Alle Klassen in .NET Framework, die IEnumerable<T> implementieren, können durch Aufrufen der AsQueryable-Erweiterungsmethode erweitert werden. Das heißt, dass die meisten Listen, Arrays und Auflistungen effizient als ADO.NET Data Services bereitgestellt werden können.

LINQ-Abfragen funktionieren auch mit Datenquellen, die IEnumerable<T> oder IQueryable<T> implementieren. Wenn das zugrunde liegende Datenmodell für einen ADO.NET Data Service mittels CLR-Objekten definiert wird, werden Anforderungs-URIs in LINQ-Abfragen konvertiert. Zwischen CLR-Objekten und Ressourcen von ADO.NET Data Services wird eine vollständige Zuordnung definiert. Durch die Zuordnung von CLR-Objekten zu ADO.NET-Entitätenmengen können ADO.NET Data Services jede Datenquelle bereitstellen, die als Array, Liste oder Auflistung in den Speicher eingelesen werden kann.

Beispiel 1: CLR-Klassen zu Ressourcen von ADO.NET Data Services

Das folgende URI-Beispiel zeigt die Zuordnung zwischen CLR-Konstrukten und Ressourcen von ADO.NET Data Services. Klassen, die die IQueryable<T>-Schnittstelle implementieren, werden als Entitätenmengen dargestellt.

Für das Beispiel wird die AsQueryable-Erweiterungsmethode verwendet, um ein Array von Customers in das IQueryable<T>-Format zu konvertieren. Das Array von Customers ist hierbei einfach konstruiert, die Anwendungsdaten könnten jedoch aus fast jeder Quelle gelesen werden.

Die Kommentare im Codebeispiel dienen dazu, die Zuordnung zwischen CLR-Typen und Ressourcentypen von ADO.NET Data Services zu verdeutlichen.

namespace Accounting  // Namespace
{
    public class DataModel  // EntityContainer
    {
        public IQueryable<Customer> Customers  // EntitySet
        {
            get
            {
                return new Customer[] { new Customer(1, "name1"),
                               new Customer(2,
                              "name2") }.AsQueryable<Customer>();
            }
        }
    }

    public class Customer  // EntityType
    {
        private int _ID;
        private string _name;
        private Address _address;

        public Customer(int i, string name)
        {
            _ID = i;
            _name = name;
            _address.Line1 = "Line" + i;
            _address.Line2 = "Line" + i;
        }

        [DataWebKeyAttribute]
        public int ID  // Entity Type Key
        {
            get { return _ID; }
        }

        public string CustName   // Property
        {
            get { return _name; }
        }

        public Address Address   // Property
        {
            get { return _address; }
        }

    }


    public struct Address   // ComplexType
    {
        private string line1;
        private string line2;

        public string Line1   // Property
        {
            get { return this.line1; }
            set { this.line1 = value; }
        }

        public string Line2   // Property
        {
            get { return this.line2; }
            set { this.line2 = value; }
        }
    }
}

Beim Zuordnen einer CLR-Entität zu einer Ressource von ADO.NET Data Services wird die Schreibweise des CLR-Namens von der zugeordneten Ressource von ADO.NET Data Services kopiert. Die CLR-Typen, die den Ressourcen von ADO.NET Data Services entsprechen, wie durch die Kommentare im vorherigen Code angegeben, sind in der folgenden Liste beschrieben.

Entitätscontainer und Entitätenmengen

  • Mit einer einzelnen öffentlichen CLR-Klasse (C1) innerhalb eines explizit definierten Namespace werden alle Entitätenmengen der höchsten Ebene im Modell definiert. Auf Ressourcen der höchsten Ebene kann mithilfe des ersten Pfadsegments in einem URI zugegriffen werden.

  • Bei dem Namespace, in dem die Klasse C1 vorhanden ist, handelt es sich um den Namespace, der C1 als Entitätscontainer identifiziert. Dies gilt auch dann, wenn C1 ein abgeleiteter Typ ist.

  • Der Name der Klasse C1 stellt den Entitätscontainer dar. Für den Namespace kann ein einziger Entitätscontainer definiert werden. Dies gilt auch dann, wenn C1 ein abgeleiteter Typ ist.

  • Jede Entitätenmenge muss als öffentliche Eigenschaft (P1) der Klasse C1 mit einem Rückgabetyp von IQueryable<T> dargestellt sein. Null oder mehr solcher Eigenschaften können in der Klasse C1 oder – wenn es sich bei der Klasse um einen abgeleiteten Typ handelt – in einer ihrer übergeordneten Klassen vorhanden sein .

    • T stellt den Entitätstyp innerhalb der Entitätenmenge dar.

    • T muss über eine Eigenschaft verfügen, die als Entitätsschlüssel geeignet ist, damit die Eigenschaft C1 als Entitätenmenge erkannt wird. Wenn keine solche Schlüsseleigenschaft existiert, wird P1 übersprungen, und C1 wird vom ADO.NET Data Services-Datendienst nicht als Darstellung einer Entitätenmenge angesehen.

    • Derselbe Typ T kann nicht von mehr als einer Eigenschaft in Klasse C1 oder einer übergeordneten Klasse von C1 zurückgegeben werden. Diese CLR-basierte Modelldefinition unterstützt kein Einbinden des gleichen Entitätstyps – in diesem Fall durch die Klasse T dargestellt – in mehrere Entitätenmengen. Mehrere Entitätenmengen pro Typ können im Entity Framework implementiert werden, jedoch nicht als von ADO.NET Data Services bereitgestellte Klassen.

  • Eine öffentliche CLR-Klasse (C1) stellt einen Entitätstyp dar.

  • Um als Entitätstyp erkannt zu werden, muss eine Klasse über eine oder mehrere Eigenschaften verfügen, die den Schlüssel des Typs darstellen. Eine solche Eigenschaft oder Gruppe von Eigenschaften wird zum Schlüssel für den Entitätstyp. Folgende Regeln gelten für Eigenschaften, die einen Schlüssel darstellen:

    • Öffentliche Eigenschaft mit dem Namen ID.

    • Öffentliche Eigenschaft mit dem Namen <className>ID.

    • Öffentliche Eigenschaften, die mit dem DataWebKeyAttribute-Attribut gekennzeichnet sind.

    • Wenn eine Klasse eine mit DataWebKeyAttribute gekennzeichnete Eigenschaft oder Gruppe von Eigenschaften enthält, werden diese Eigenschaften als Schlüssel verwendet, und die ersten beiden Regeln werden ignoriert. Wenn das Attribut in keinen Eigenschaften enthalten ist, wird die Schlüsseleigenschaft des Entitätstyps von den Eigenschaften festgelegt, die die ersten beiden Regeln erfüllen. Wenn mehrere Eigenschaften die Regeln erfüllen, verfügt der Entitätstyp per Definition über einen zusammengesetzten Schlüssel.

  • Wenn die Klasse C1 Teil einer Hierarchie ist, wird die Klassenhierarchie den folgenden Regeln entsprechend in eine Entitätstypenhierarchie übersetzt:

    • Die CLR-Klasse, die sich am nächsten zum Stamm der Klassenhierarchie befindet und die eine gültige Schlüsseleigenschaft enthält, wird zum Stamm der Entitätstypenhierarchie. Wenn die Klasse C1 nicht der Stamm der CLR-Klassenhierarchie ist, in der sie enthalten ist, wird davon ausgegangen, dass die Eigenschaften, die von den Klassen über C1 in der Hierarchie deklariert werden, von C1 deklariert werden.
  • Jede von der Klasse C1 deklarierte Eigenschaft (P) wird in eine Eigenschaft des Entitätstyps übersetzt, wenn die CLR-Eigenschaft alle folgenden Konventionen erfüllt:

    • Die CLR-Eigenschaft muss einen öffentlichen Gültigkeitsbereich haben.

    • Die CLR-Eigenschaft muss eine get-Methode für die Eigenschaft implementieren.

    • Die CLR-Eigenschaft darf kein Indexer sein.

    • Wenn es sich bei dem Rückgabetyp der Eigenschaft P um einen primitiven Typ handelt und der Typ einem EDM-Typ entspricht, muss die Eigenschaft als Eigenschaft dargestellt werden. Eine Zuordnung von EDM-Typen zu CLR-Typen finden Sie unter ADO.NET Data Services-Inhaltstypen.

    • Wenn es sich beim Rückgabetyp der Eigenschaft P um einen Referenztyp handelt und der Typ oder eines der übergeordneten Objekte (im Fall eines abgeleiteten Typs) einen Entitätstyp darstellt, stellt P einen 1:1-Navigationslink dar.

    • Wenn der Rückgabetyp der Eigenschaft P IEnumerable<T> ist und T einen Entitätstyp darstellt, stellt P einen 1:n-Navigationslink dar.

    • Wenn es sich bei dem Rückgabetyp der Eigenschaft P um einen Werttyp handelt, stellt P einen komplexen Typ dar.

Komplexe Typen

  • Ein öffentlicher CLR-Werttyp (V1) stellt einen komplexen Typ dar.

  • Jede Eigenschaft des Werttyps V1 wird in eine Eigenschaft eines komplexen Typs übersetzt. Komplexe Typen folgen bei der Festlegung, ob eine CLR-Eigenschaft einer Eigenschaft zugeordnet wird, ähnlichen Regeln wie Entitätstypen.

    • Die CLR-Eigenschaft muss einen öffentlichen Gültigkeitsbereich haben.

    • Die CLR-Eigenschaft muss eine get-Methode für die Eigenschaft implementieren.

    • Die CLR-Eigenschaft darf kein Indexer sein.

    • Wenn es sich beim Rückgabetyp der Eigenschaft P um einen Referenztyp handelt und der Typ oder eines der übergeordneten Objekte (im Fall eines abgeleiteten Typs) einen Entitätstyp darstellt, stellt P einen 1:1-Navigationslink dar.

Beispiel 2: CLR-Klassen zu Ressourcen von ADO.NET Data Services

Das folgende URI-Beispiel zeigt CLR-Klassen, die eine Vererbung beinhalten, um Ressourcentypen von ADO.NET Data Services zu implementieren.

namespace Accounting
{
    public class DataModel
    {
        public IQueryable<Customer> Customers
        {
            get
            {
                return new Customer[] { new Customer(1, "name1"),
                    new Customer(2, "name2") }.AsQueryable<Customer>();
            }
        }

        public IQueryable<Order> Orders
        {
            get
            {
                return new Order[] { new Order(1, "order1"),
                   new Order(2, "order2") }.AsQueryable<Order>();
            }
        }
    }


    public class DerivedDataModel : DataModel
    {
        public IQueryable<HumanResources.Employee> Employees
        {
            get { return new HumanResources.Employee[] { new 
                        HumanResources.Employee(1, "EmpName1"), new 
                        HumanResources.Employee(2, "EmpName2") 
                         }.AsQueryable<HumanResources.Employee>(); 
               } 
        }
    }

    public class Person
    {
        protected int _ID;
        public Person() { }
        public Person(int i)
        {
            _ID = i;
        }

        [DataWebKeyAttribute]
        public int ID
        {
            get { return _ID; }
        }
    }

    public class Customer : Person
    {
        private string _name;
        private Address _address;
        List<Order> _orders;

        public Customer(int i, string name)
        {
            _ID = i;
            _name = name;
            _orders = new List<Order>();
            if (i == 1) { _orders.Add(new Order(1, "order1")); }
            if (i == 2) { _orders.Add(new Order(2, "order2")); }
            _address.Line1 = "Line" + i;
            _address.Line2 = "Line" + i;
        }

        public string CustName
        {
            get { return _name; }
        }

        public Address Address
        {
            get { return _address; }
        }

        public IList<Order> Orders
        {
            get { return _orders; }
        }
    }

    public class Order
    {
        private int _ID;
        private string _name;

        public Order(int i, string name)
        {
            _ID = i;
            _name = name;
        }

        [DataWebKeyAttribute]
        public int OrderKey
        {
            get { return _ID; }
        }

        public string OrderName
        {
            get { return _name; }
        }
    }

    public struct Address
    {
        private string line1;
        private string line2;

        public string Line1
        {
            get { return this.line1; }
            set { this.line1 = value; }
        }

        public string Line2
        {
            get { return this.line2; }
            set { this.line2 = value; }
        }
    }
}

namespace HumanResources
{
    public class Employee
    {
        private int _ID;
        private string _name;

        public Employee(int i, string name)
        {
            _ID = i;
            _name = name;
        }

        public int ID
        {
            get { return _ID; }
        }

        public string EmpName
        {
            get { return _name; }
        }
    }
}

Schreib-/Aktualisierungsunterstützung

Um die Unterstützung zum Erstellen, Aktualisieren und Löschen für ein CLR-Datenmodell zu aktivieren, muss die Klasse, mit der die Entitätenmengen der höchsten Ebene modelliert werden, die IUpdatable-Schnittstelle implementieren. In Bezug auf das vorherige Beispiel 2, CLR-Klassen zu Ressourcen von ADO.NET Data Services, wäre zum Implementieren der IUpdatable-Schnittstelle die Accounting.DataModel-Klasse erforderlich.

Siehe auch

Konzepte

ADO.NET Data Service-Spezifikationen

Weitere Ressourcen

Entity Data Model