Condividi tramite


Creare il livello di accesso ai dati

di Erik Reitan

Questa serie di esercitazioni illustra le nozioni di base per la creazione di un'applicazione Web Forms ASP.NET usando ASP.NET 4.5 e Microsoft Visual Studio Express 2013 per Web. Per questa serie di esercitazioni è disponibile un progetto di Visual Studio 2013 con codice sorgente C#.

Questa esercitazione descrive come creare, accedere ed esaminare i dati da un database usando Web Forms ASP.NET ed Entity Framework Code First. Questa esercitazione si basa sull'esercitazione precedente "Creare il progetto" ed è parte della serie di esercitazioni Wingtip Toy Store. Al termine di questa esercitazione, si creerà un gruppo di classi di accesso ai dati che si trovano nella cartella Models del progetto.

Contenuto dell'esercitazione:

  • Come creare i modelli di dati.
  • Come inizializzare e inizializzare il database.
  • Come aggiornare e configurare l'applicazione per supportare il database.

Queste sono le funzionalità introdotte nell'esercitazione:

  • Entity Framework Code First
  • DB locale
  • Annotazioni dei dati

Creazione dei modelli di dati

Entity Framework è un framework ORM (Object-Relational Mapping). Consente di usare dati relazionali come oggetti, eliminando la maggior parte del codice di accesso ai dati che in genere è necessario scrivere. Usando Entity Framework, è possibile eseguire query usando LINQ, quindi recuperare e modificare i dati come oggetti fortemente tipizzati. LINQ fornisce modelli per l'esecuzione di query e l'aggiornamento dei dati. L'uso di Entity Framework consente di concentrarsi sulla creazione del resto dell'applicazione, invece di concentrarsi sui concetti fondamentali sull'accesso ai dati. Più avanti in questa serie di esercitazioni verrà illustrato come usare i dati per popolare le query di spostamento e prodotto.

Entity Framework supporta un paradigma di sviluppo denominato Code First. Code First consente di definire i modelli di dati usando classi. Una classe è un costrutto che consente di creare tipi personalizzati raggruppando insieme variabili di altri tipi, metodi e eventi. È possibile eseguire il mapping delle classi a un database esistente o usarle per generare un database. In questa esercitazione si creeranno i modelli di dati scrivendo classi del modello di dati. Sarà quindi possibile consentire a Entity Framework di creare il database in tempo reale da queste nuove classi.

Si inizierà creando le classi di entità che definiscono i modelli di dati per l'applicazione Web Forms. Si creerà quindi una classe di contesto che gestisce le classi di entità e fornisce l'accesso ai dati al database. Verrà anche creata una classe di inizializzatore che verrà usata per popolare il database.

Entity Framework e riferimenti

Per impostazione predefinita, Entity Framework viene incluso quando si crea una nuova applicazione Web ASP.NET usando il modello di Web Forms. Entity Framework può essere installato, disinstallato e aggiornato come pacchetto NuGet.

Questo pacchetto NuGet include gli assembly di runtime seguenti all'interno del progetto:

  • EntityFramework.dll: tutto il codice Common Runtime usato da Entity Framework
  • EntityFramework.SqlServer.dll: provider di SQL Server Microsoft per Entity Framework

Classi di entità

Le classi create per definire lo schema dei dati sono denominate classi di entità. Se non si ha familiarità con la progettazione del database, considerare le classi di entità come definizioni di tabella di un database. Ogni proprietà nella classe specifica una colonna nella tabella del database. Queste classi forniscono un'interfaccia semplice relazionale a oggetti tra il codice orientato agli oggetti e la struttura di tabella relazionale del database.

In questa esercitazione si inizierà aggiungendo classi di entità semplici che rappresentano gli schemi per prodotti e categorie. La classe products conterrà le definizioni per ogni prodotto. Il nome di ogni membro della classe di prodotto sarà ProductID, , ProductName, Description, ImagePathUnitPrice, CategoryID, e Category. La classe category conterrà definizioni per ogni categoria a cui può appartenere un prodotto, ad esempio Car, Boat o Plane. Il nome di ogni membro della classe di categoria sarà CategoryID, , CategoryNameDescriptione Products. Ogni prodotto appartiene a una delle categorie. Queste classi di entità verranno aggiunte alla cartella Models esistente del progetto.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Modelli e quindi scegliere Aggiungi ->Nuovo elemento.

    Screenshot della finestra Esplora soluzioni con la cartella Models evidenziata e i menu a discesa Aggiungi e Nuovo elemento selezionati.

    La finestra di dialogo Aggiungi nuovo elemento viene visualizzata.

  2. In Visual C# dal riquadro Installato a sinistra selezionare Codice.

    Screenshot della finestra Aggiungi nuovo elemento che mostra il riquadro Installato a sinistra con Visual C# aperto e Il codice selezionato.

  3. Selezionare Classe nel riquadro centrale e assegnare alla nuova classe il nome Product.cs.

  4. Scegliere Aggiungi.
    Il nuovo file di classe viene visualizzato nell'editor.

  5. Sostituire il codice predefinito con il codice seguente:

    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class Product
        {
            [ScaffoldColumn(false)]
            public int ProductID { get; set; }
    
            [Required, StringLength(100), Display(Name = "Name")]
            public string ProductName { get; set; }
    
            [Required, StringLength(10000), Display(Name = "Product Description"), DataType(DataType.MultilineText)]
            public string Description { get; set; }
    
            public string ImagePath { get; set; }
    
            [Display(Name = "Price")]
            public double? UnitPrice { get; set; }
    
            public int? CategoryID { get; set; }
    
            public virtual Category Category { get; set; }
        }
    }
    
  6. Creare un'altra classe ripetendo i passaggi da 1 a 4, ma denominare la nuova classe Category.cs e sostituire il codice predefinito con il codice seguente:

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class Category
        {
            [ScaffoldColumn(false)]
            public int CategoryID { get; set; }
    
            [Required, StringLength(100), Display(Name = "Name")]
            public string CategoryName { get; set; }
    
            [Display(Name = "Product Description")]
            public string Description { get; set; }
    
            public virtual ICollection<Product> Products { get; set; }
        }
    }
    

Come accennato in precedenza, la Category classe rappresenta il tipo di prodotto che l'applicazione è progettata per la vendita (ad esempio "Cars", "Boats", "Rockets" e così via) e la Product classe rappresenta i singoli prodotti (giocattoli) nel database. Ogni istanza di un Product oggetto corrisponderà a una riga all'interno di una tabella di database relazionale e ogni proprietà della classe Product eseguirà il mapping a una colonna nella tabella di database relazionale. Più avanti in questa esercitazione verranno esaminati i dati del prodotto contenuti nel database.

Annotazioni dei dati

È possibile che alcuni membri delle classi abbiano attributi che specificano dettagli sul membro, ad esempio [ScaffoldColumn(false)]. Si tratta di annotazioni di dati. Gli attributi di annotazione dati possono descrivere come convalidare l'input dell'utente per tale membro, specificare la formattazione e specificare la modalità di modellazione durante la creazione del database.

Classe Context

Per iniziare a usare le classi per l'accesso ai dati, è necessario definire una classe di contesto. Come accennato in precedenza, la classe di contesto gestisce le classi di entità ( ad esempio la Product classe e la Category classe ) e fornisce l'accesso ai dati al database.

Questa procedura aggiunge una nuova classe di contesto C# alla cartella Models .

  1. Fare clic con il pulsante destro del mouse sulla cartella Modelli e quindi scegliere Aggiungi ->Nuovo elemento.
    La finestra di dialogo Aggiungi nuovo elemento viene visualizzata.

  2. Selezionare Classe nel riquadro centrale, denominarla ProductContext.cs e fare clic su Aggiungi.

  3. Sostituire il codice predefinito contenuto nella classe con il codice seguente:

    using System.Data.Entity;
    namespace WingtipToys.Models
    {
        public class ProductContext : DbContext
        {
            public ProductContext() : base("WingtipToys")
            {
            }
            public DbSet<Category> Categories { get; set; }
            public DbSet<Product> Products { get; set; }
        }
    }
    

Questo codice aggiunge lo System.Data.Entity spazio dei nomi in modo che sia possibile accedere a tutte le funzionalità di base di Entity Framework, che include la possibilità di eseguire query, inserire, aggiornare ed eliminare dati usando oggetti fortemente tipizzati.

La classe rappresenta il ProductContext contesto del database del prodotto Entity Framework, che gestisce il recupero, l'archiviazione e l'aggiornamento Product delle istanze di classe nel database. La ProductContext classe deriva dalla DbContext classe base fornita da Entity Framework.

Classe Initializer

È necessario eseguire una logica personalizzata per inizializzare il database la prima volta che viene usato il contesto. In questo modo i dati di inizializzazione verranno aggiunti al database in modo da poter visualizzare immediatamente prodotti e categorie.

Questa procedura aggiunge una nuova classe di inizializzatore C# alla cartella Models .

  1. Creare un altro Class elemento nella cartella Models e denominarlo ProductDatabaseInitializer.cs.

  2. Sostituire il codice predefinito contenuto nella classe con il codice seguente:

    using System.Collections.Generic;
    using System.Data.Entity;
    
    namespace WingtipToys.Models
    {
      public class ProductDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProductContext>
      {
        protected override void Seed(ProductContext context)
        {
          GetCategories().ForEach(c => context.Categories.Add(c));
          GetProducts().ForEach(p => context.Products.Add(p));
        }
    
        private static List<Category> GetCategories()
        {
          var categories = new List<Category> {
                    new Category
                    {
                        CategoryID = 1,
                        CategoryName = "Cars"
                    },
                    new Category
                    {
                        CategoryID = 2,
                        CategoryName = "Planes"
                    },
                    new Category
                    {
                        CategoryID = 3,
                        CategoryName = "Trucks"
                    },
                    new Category
                    {
                        CategoryID = 4,
                        CategoryName = "Boats"
                    },
                    new Category
                    {
                        CategoryID = 5,
                        CategoryName = "Rockets"
                    },
                };
    
          return categories;
        }
    
        private static List<Product> GetProducts()
        {
          var products = new List<Product> {
                    new Product
                    {
                        ProductID = 1,
                        ProductName = "Convertible Car",
                        Description = "This convertible car is fast! The engine is powered by a neutrino based battery (not included)." + 
                                      "Power it up and let it go!", 
                        ImagePath="carconvert.png",
                        UnitPrice = 22.50,
                        CategoryID = 1
                   },
                    new Product 
                    {
                        ProductID = 2,
                        ProductName = "Old-time Car",
                        Description = "There's nothing old about this toy car, except it's looks. Compatible with other old toy cars.",
                        ImagePath="carearly.png",
                        UnitPrice = 15.95,
                         CategoryID = 1
                   },
                    new Product
                    {
                        ProductID = 3,
                        ProductName = "Fast Car",
                        Description = "Yes this car is fast, but it also floats in water.",
                        ImagePath="carfast.png",
                        UnitPrice = 32.99,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 4,
                        ProductName = "Super Fast Car",
                        Description = "Use this super fast car to entertain guests. Lights and doors work!",
                        ImagePath="carfaster.png",
                        UnitPrice = 8.95,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 5,
                        ProductName = "Old Style Racer",
                        Description = "This old style racer can fly (with user assistance). Gravity controls flight duration." + 
                                      "No batteries required.",
                        ImagePath="carracer.png",
                        UnitPrice = 34.95,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 6,
                        ProductName = "Ace Plane",
                        Description = "Authentic airplane toy. Features realistic color and details.",
                        ImagePath="planeace.png",
                        UnitPrice = 95.00,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 7,
                        ProductName = "Glider",
                        Description = "This fun glider is made from real balsa wood. Some assembly required.",
                        ImagePath="planeglider.png",
                        UnitPrice = 4.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 8,
                        ProductName = "Paper Plane",
                        Description = "This paper plane is like no other paper plane. Some folding required.",
                        ImagePath="planepaper.png",
                        UnitPrice = 2.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 9,
                        ProductName = "Propeller Plane",
                        Description = "Rubber band powered plane features two wheels.",
                        ImagePath="planeprop.png",
                        UnitPrice = 32.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 10,
                        ProductName = "Early Truck",
                        Description = "This toy truck has a real gas powered engine. Requires regular tune ups.",
                        ImagePath="truckearly.png",
                        UnitPrice = 15.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 11,
                        ProductName = "Fire Truck",
                        Description = "You will have endless fun with this one quarter sized fire truck.",
                        ImagePath="truckfire.png",
                        UnitPrice = 26.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 12,
                        ProductName = "Big Truck",
                        Description = "This fun toy truck can be used to tow other trucks that are not as big.",
                        ImagePath="truckbig.png",
                        UnitPrice = 29.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 13,
                        ProductName = "Big Ship",
                        Description = "Is it a boat or a ship. Let this floating vehicle decide by using its " + 
                                      "artifically intelligent computer brain!",
                        ImagePath="boatbig.png",
                        UnitPrice = 95.00,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 14,
                        ProductName = "Paper Boat",
                        Description = "Floating fun for all! This toy boat can be assembled in seconds. Floats for minutes!" + 
                                      "Some folding required.",
                        ImagePath="boatpaper.png",
                        UnitPrice = 4.95,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 15,
                        ProductName = "Sail Boat",
                        Description = "Put this fun toy sail boat in the water and let it go!",
                        ImagePath="boatsail.png",
                        UnitPrice = 42.95,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 16,
                        ProductName = "Rocket",
                        Description = "This fun rocket will travel up to a height of 200 feet.",
                        ImagePath="rocket.png",
                        UnitPrice = 122.95,
                        CategoryID = 5
                    }
                };
    
          return products;
        }
      }
    }
    

Come si può notare dal codice precedente, quando il database viene creato e inizializzato, la Seed proprietà viene sottoposta a override e impostata. Quando la Seed proprietà è impostata, i valori delle categorie e dei prodotti vengono usati per popolare il database. Se si tenta di aggiornare i dati di inizializzazione modificando il codice precedente dopo la creazione del database, non verranno visualizzati aggiornamenti quando si esegue l'applicazione Web. Il motivo è che il codice precedente usa un'implementazione della DropCreateDatabaseIfModelChanges classe per riconoscere se il modello (schema) è stato modificato prima di reimpostare i dati di inizializzazione. Se non vengono apportate modifiche alle Category classi di entità e Product , il database non verrà reinizializzato con i dati di inizializzazione.

Nota

Se si vuole ricreare il database ogni volta che è stata eseguita l'applicazione, è possibile usare la DropCreateDatabaseAlways classe anziché la DropCreateDatabaseIfModelChanges classe . Tuttavia, per questa serie di esercitazioni, usare la DropCreateDatabaseIfModelChanges classe .

A questo punto di questa esercitazione si avrà una cartella Models con quattro nuove classi e una classe predefinita:

Creare il livello di accesso ai dati - cartella Models

Configurazione dell'applicazione per l'uso del modello di dati

Dopo aver creato le classi che rappresentano i dati, è necessario configurare l'applicazione per l'uso delle classi. Nel file Global.asax aggiungere codice che inizializza il modello. Nel file Web.config si aggiungono informazioni che indicano all'applicazione il database che verrà usato per archiviare i dati rappresentati dalle nuove classi di dati. Il file Global.asax può essere usato per gestire gli eventi o i metodi dell'applicazione. Il file Web.config consente di controllare la configurazione dell'applicazione Web ASP.NET.

Aggiornamento del file Global.asax

Per inizializzare i modelli di dati all'avvio dell'applicazione, si aggiornerà il Application_Start gestore nel file Global.asax.cs .

Nota

In Esplora soluzioni è possibile selezionare il file Global.asax o il file Global.asax.cs per modificare il file Global.asax.cs.

  1. Aggiungere il codice seguente evidenziato in giallo al Application_Start metodo nel file Global.asax.cs .

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.SessionState;
    using System.Data.Entity;
    using WingtipToys.Models;
    
    namespace WingtipToys
    {
        public class Global : HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
                // Code that runs on application startup
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
    
                // Initialize the product database.
                Database.SetInitializer(new ProductDatabaseInitializer());
            }
        }
    }
    

Nota

Il browser deve supportare HTML5 per visualizzare il codice evidenziato in giallo durante la visualizzazione di questa serie di esercitazioni in un browser.

Come illustrato nel codice precedente, all'avvio dell'applicazione, l'applicazione specifica l'inizializzatore che verrà eseguito durante la prima volta che i dati vengono accessibili. Per accedere all'oggetto e all'oggetto DatabaseProductDatabaseInitializer sono necessari due spazi dei nomi aggiuntivi.

Modifica del file di Web.Config

Anche se Entity Framework Code First genererà un database in un percorso predefinito quando il database viene popolato con i dati di inizializzazione, aggiungendo informazioni di connessione personalizzate all'applicazione, viene fornito il controllo del percorso del database. Specificare questa connessione al database usando una stringa di connessione nel file diWeb.config dell'applicazione nella radice del progetto. Aggiungendo una nuova stringa di connessione, è possibile indirizzare la posizione del database (wingtiptoys.mdf) da compilare nella directory dati dell'applicazione (App_Data), anziché nella posizione predefinita. L'esecuzione di questa modifica consente di trovare ed esaminare il file di database più avanti in questa esercitazione.

  1. In Esplora soluzioni trovare e aprire il file diWeb.config.

  2. Aggiungere la stringa di connessione evidenziata in giallo alla <connectionStrings> sezione del file Web.config come indicato di seguito:

    <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-WingtipToys-20131119102907.mdf;Initial Catalog=aspnet-WingtipToys-20131119102907;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    <add name="WingtipToys"
    connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\wingtiptoys.mdf;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    </connectionStrings>
    

Quando l'applicazione viene eseguita per la prima volta, verrà compilato il database nel percorso specificato dalla stringa di connessione. Ma prima di eseguire l'applicazione, verrà compilata prima.

Compilazione dell'applicazione

Per assicurarsi che tutte le classi e le modifiche apportate all'applicazione Web funzionino, è necessario compilare l'applicazione.

  1. Dal menu Debug selezionare Compila WingtipToys.
    La finestra Output viene visualizzata e, se tutto è andato bene, viene visualizzato un messaggio riuscito .

    Creare il livello di accesso ai dati - Windows di output

Se si verifica un errore, controllare nuovamente i passaggi precedenti. Le informazioni nella finestra Output indicano quali file hanno un problema e dove è necessaria una modifica nel file. Queste informazioni consentono di determinare quale parte dei passaggi precedenti devono essere esaminati e risolti nel progetto.

Riepilogo

In questa esercitazione della serie è stato creato il modello di dati, nonché aggiunto il codice che verrà usato per inizializzare e inizializzare il database. L'applicazione è stata configurata anche per l'uso dei modelli di dati quando l'applicazione viene eseguita.

Nell'esercitazione successiva si aggiornerà l'interfaccia utente, si aggiungerà lo spostamento e si recuperano i dati dal database. Ciò comporterà la creazione automatica del database in base alle classi di entità create in questa esercitazione.

Risorse aggiuntive

Cenni preliminari su Entity Framework
Guida per principianti alla ADO.NET Entity Framework
Code First Development with Entity Framework Code FirstRelationships Fluent API
Annotazioni dei dati per Code First
Miglioramenti alla produttività per Entity Framework