Condividi tramite


Modello di dati (framework di ADO.NET Data Services)

ADO.NET Data Services supporta i modelli ADO.NET Entity Framework a livello nativo e fornisce un'estensione in base a cui è possibile definire un modello di dati utilizzando oggetti CRL (Common Language Runtime). Per illustrare i dati distribuiti dal framework di ADO.NET Data Services, viene utilizzata la terminologia EDM (Entity Data Model), in particolare il linguaggio CSDL (Conceptual Schema Definition Language) e termini quali EntitySet, EntityType, PropertyAssociation, AssociationSet e così via. Per la definizione di questi termini, vedere Terminologia del framework di ADO.NET Data Services. Per ulteriori informazioni su CSDL, vedere Specifiche EDM.

Riducendo le origini dati a singole regole di grammatica e convenzioni URI uniformi, ADO.NET Data Services consente di distribuire rappresentazioni coerenti di dati indipendentemente dall'origine dati sottostante. Quando viene utilizzato un modello di Entity Framework, la configurazione di un servizio dati è superflua. Per i modelli basati su CLR, è stato definito un mapping tra gli oggetti CLR e i tipi EDM.

Modello di dati EDM

Nel modello EDM (Entity Data Model), ADO.NET Data Services interagisce con il livello Object Services di Entity Framework, ovvero con un contesto CLR programmabile. Sebbene il contesto di programmazione e il modello concettuale possano essere prodotti manualmente, l'approccio consigliato è quello di utilizzare Strumenti di Entity Data Model integrati con Microsoft Visual Studio 2008 a partire dalla versione SP1.

Per un esempio di utilizzo degli strumenti EDM e Entity Framework, vedere Guida introduttiva al servizio dati (framework di ADO.NET Data Services).

Modello di dati basato su CLR

In ADO.NET Data Services le richieste URI vengono convertite in operazioni sui dati indirizzati dalla sintassi URI. Quando il modello di dati è basato su Entity Framework, gli URI vengono convertiti in chiamate al metodo Object Services. L'oggetto ObjectContext di Entity Framework distribuisce i set di dati in base a ObjectQuery<T> e ObjectQuery<T> implementa IQueryable<T>.

È possibile distribuire sotto forma di servizio dati ADO.NET qualsiasi tecnologia o provider che distribuisce i dati implementando un derivato di IQueryable. Il metodo di estensione AsQueryable , disponibile a partire da .NET Framework 3.5, può essere utilizzato con oggetti che implementano IEnumerable<T>. Tutte le classi di .NET Framework che implementano IEnumerable<T> possono essere estese chiamando il metodo di estensione AsQueryable. Ciò significa che è possibile distribuire in maniera efficiente sotto forma di servizio ADO.NET Data Services la maggior parte degli elenchi, matrici e insiemi.

Anche le query LINQ funzionano con origini dati che implementano IEnumerable<T> o IQueryable<T>. Quando il modello di dati sottostante per un servizio ADO.NET Data Service viene definito mediante oggetti CLR, gli URI di richiesta vengono convertiti in query LINQ. Tra gli oggetti CLR e le risorse ADO.NET Data Services viene definito un mapping completo. In ADO.NET Data Services, il mapping degli oggetti CLR ai set di entità ADO.NET consente di distribuire qualsiasi origine dati che possa essere letta in memoria come matrice, elenco o insieme.

Esempio 1: Classi CLR a risorse ADO.NET Data Service

Nell'esempio seguente viene illustrato il mapping tra i costrutti CLR e le risorse ADO.NET Data Services. Le classi che implementano l'interfaccia IQueryable<T> vengono rappresentate come set di entità.

Nell'esempio seguente viene utilizzato il metodo di estensione AsQueryable per convertire una matrice di oggetti Customers nel formato IQueryable<T>. La matrice di oggetti Customers dell'esempio viene costruita in modo semplice, ma i dati dell'applicazione possono essere letti da praticamente qualsiasi origine.

L'esempio di codice viene annotato per indicare come i tipi CLR eseguono il mapping ai tipi di risorse ADO.NET Data Services.

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

Quando si esegue il mapping di un'entità CLR a una risorsa ADO.NET Data Services, l'utilizzo di maiuscole e minuscole del nome CLR viene copiato dalla risorsa ADO.NET Data Services associata. Nell'elenco riportato di seguito vengono illustrati i tipi CLR corrispondenti alle risorse ADO.NET Data Services, secondo quanto indicato dai commenti del codice precedente.

Contenitori di entità e set di entità

  • Per definire tutti i set di entità di livello superiore nel modello, viene utilizzata un'unica classe CLR pubblica (C1) all'interno di uno spazio dei nomi definito in modo esplicito. Le risorse di livello superiore sono accessibili utilizzando il primo segmento di percorso in un URI.

  • Lo spazio dei nomi in cui è presente la classe C1 è lo spazio dei nomi che identifica la classe C1 come contenitore di entità. Ciò rappresenta una costante anche se C1 è un tipo derivato.

  • Il nome della classe C1 rappresenta il contenitore dell'entità. È possibile definire un contenitore di entità singolo per lo spazio dei nomi. Ciò rappresenta una costante anche se C1 è un tipo derivato.

  • Ogni set di entità deve essere rappresentato come una proprietà pubblica (P1) della classe C1 con tipo restituito IQueryable<T>. Nella classe C1 o, se la classe è un tipo derivato, in una delle classi padre, possono essere presenti zero o più proprietà.

    • T rappresenta il tipo di entità all'interno del set di entità.

    • T deve disporre di una proprietà appropriata per costituire una chiave di entità affinché la proprietà C1 possa essere considerata un set di entità. Se non è presente alcuna proprietà di chiave appropriata, la proprietà P1 viene ignorata e la classe C1 non viene considerata rappresentativa di un set di entità dal servizio dati ADO.NET Data Services.

    • Lo stesso tipo T non può essere restituito da più di una proprietà nella classe C1 o in una classe padre di C1. Questa definizione del modello basata su CLR non supporta l'inserimento dello stesso tipo di entità, rappresentato in questo caso dalla classe T, in più set di entità. In Entity Framework è possibile implementare più set di entità per tipo, ma non come classi distribuite da ADO.NET Data Services.

Tipi di entità, proprietà e collegamenti di navigazione

  • Una classe CLR pubblica (C1) rappresenta un tipo di entità.

  • Per essere riconosciuta come tipo di entità, una classe deve disporre di una o più proprietà che rappresentano la chiave del tipo. Tale proprietà o gruppo di proprietà diventa la chiave per il tipo di entità. Le regole per le proprietà che rappresentano una chiave sono:

    • ID denominato della proprietà pubblica.

    • ID <className> denominato della proprietà pubblica.

    • Proprietà pubbliche contrassegnate con l'attributo DataWebKeyAttribute.

    • Se una classe contiene una proprietà o un gruppo di proprietà contrassegnato da DataWebKeyAttribute, tali proprietà sono utilizzate come chiave e le prime due regole vengono ignorate. Se nessuna proprietà contiene l'attributo, le proprietà corrispondenti alle prime due regole determinano la proprietà della chiave del tipo di entità. Se più proprietà corrispondono alle regole, il tipo di entità dispone, per definizione, di una chiave composta.

  • Se la classe C1 fa parte di una gerarchia, la gerarchia delle classi viene convertita in una gerarchia di tipi di entità applicando le regole seguenti:

    • La classe CLR più vicina alla radice della gerarchia delle classi che include una proprietà di chiave valida diventa la radice della gerarchia dei tipi di entità. Se la classe C1 non è la radice della gerarchia di classi CLR di cui fa parte, le proprietà dichiarate dalle classi superiori a C1 nella gerarchia vengono considerate dichiarate da C1.
  • Ogni proprietà (P) dichiarata dalla classe C1 viene convertita in una proprietà del tipo di entità se la proprietà CLR è conforme a tutte le convenzioni seguenti:

    • La proprietà CLR deve disporre di ambito pubblico.

    • La proprietà CLR deve implementare un metodo Get per la proprietà.

    • La proprietà CLR non deve essere un indicizzatore.

    • Se per la proprietà P viene restituito un tipo primitivo e il tipo corrisponde a un tipo EDM, la proprietà deve essere rappresentata come una proprietà. Per eseguire il mapping dei tipi EDM ai tipi CLR, vedere Tipi di contenuto di ADO.NET Data Services.

    • Se per la proprietà P viene restituito un tipo di riferimento e il tipo o, nel caso di un tipo derivato, uno dei relativi oggetti padre rappresenta un tipo di entità, P rappresenta un collegamento di navigazione uno-a-uno.

    • Se per la proprietà P viene restituito IEnumerable<T> e T rappresenta un tipo di entità, P rappresenta un collegamento di navigazione uno-a-molti.

    • Se per la proprietà P viene restituito un tipo di valore, P rappresenta un tipo complesso.

Tipi complessi

  • Un tipo di valore CLR pubblico (V1) rappresenta un tipo complesso.

  • Ogni proprietà del tipo di valore V1 viene convertita in una proprietà di tipo complesso. I tipi complessi seguono regole simili ai tipi di entità per determinare se una proprietà CLR sarà mappata a una proprietà.

    • La proprietà CLR deve disporre di ambito pubblico.

    • La proprietà CLR deve implementare un metodo Get per la proprietà.

    • La proprietà CLR non deve essere un indicizzatore.

    • Se per la proprietà P viene restituito un tipo di riferimento e il tipo o, nel caso di un tipo derivato, uno dei relativi oggetti padre rappresenta un tipo di entità, P rappresenta un collegamento di navigazione uno-a-uno.

Esempio 2: Classi CLR a risorse ADO.NET Data Service

Nell'esempio riportato di seguito vengono illustrate le classi CLR che includono l'ereditarietà utilizzata per implementare tipi di risorse ADO.NET Data Services.

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

Supporto di scrittura/aggiornamento

Per abilitare il supporto per operazioni di creazione, aggiornamento ed eliminazione su un modello di dati CLR, è necessario che la classe che modella i set di entità di livello superiore implementi l'interfaccia IUpdatable. In riferimento all'esempio 2 riguardante oggetti CLR a risorse del framework di ADO.NET Data Services illustrato in precedenza, la classe Accounting.DataModel sarebbe necessaria per implementare l'interfaccia IUpdatable.

Vedere anche

Concetti

Specifiche di ADO.NET Data Service

Altre risorse

Entity Data Model