Tworzenie warstwy dostępu do danych

Autor Erik Reitan

Pobierz program Wingtip zabawki (C#) lub Pobierz książkę elektroniczną (PDF)

Ta seria samouczków zawiera informacje na temat tworzenia aplikacji ASP.NET Web Forms przy użyciu ASP.NET 4,5 i Microsoft Visual Studio Express 2013 dla sieci Web. Projekt Visual Studio 2013 z C# kodem źródłowym jest dostępny do tej serii samouczków.

W tym samouczku opisano sposób tworzenia, uzyskiwania dostępu i przeglądania danych z bazy danych przy użyciu formularzy sieci Web ASP.NET i Code First Entity Framework. Ten samouczek kompiluje się w poprzednim samouczku "Tworzenie projektu" i jest częścią serii samouczków dotyczących sklepu Wingtip. Po ukończeniu tego samouczka utworzysz grupę klas dostępu do danych, które znajdują się w folderze modele projektu.

Zawartość:

  • Jak utworzyć modele danych.
  • Jak zainicjować i wypełniać bazę danych.
  • Jak zaktualizować i skonfigurować aplikację do obsługi bazy danych.

Oto funkcje wprowadzone w samouczku:

  • Entity Framework Code First
  • LocalDB
  • Adnotacje danych

Tworzenie modeli danych

Entity Framework to struktura mapowania obiektów (ORM). Umożliwia ona korzystanie z danych relacyjnych jako obiektów, eliminując większość kodu dostępu do danych, który zwykle jest potrzebny do zapisu. Za pomocą Entity Framework można wydać zapytania przy użyciu LINQ, a następnie pobrać i manipulować danymi jako obiektami silnie wpisaną. LINQ zawiera wzorce do wykonywania zapytań i aktualizowania danych. Korzystanie z Entity Framework pozwala skupić się na tworzeniu reszty aplikacji, a nie skoncentrowaniu się na podstawowych podstawach dostępu do danych. W dalszej części tej serii samouczków pokazano, jak używać danych w celu wypełnienia nawigacji i zapytań dotyczących produktów.

Entity Framework obsługuje model programistyczny o nazwie Code First. Code First umożliwia definiowanie modeli danych przy użyciu klas. Klasa to konstrukcja, która umożliwia tworzenie własnych typów niestandardowych przez grupowanie zmiennych innych typów, metod i zdarzeń. Można mapować klasy do istniejącej bazy danych lub użyć ich do wygenerowania bazy danych. W tym samouczku utworzysz modele danych przez zapisanie klas modelu danych. Następnie można Entity Framework utworzyć bazę danych na bieżąco z tych nowych klas.

Zacznij od utworzenia klas jednostek, które definiują modele danych dla aplikacji formularzy sieci Web. Następnie utworzysz klasę kontekstu, która zarządza klasami jednostek i zapewnia dostęp do danych w bazie danych. Utworzysz również klasę inicjatora, która będzie używana do wypełniania bazy danych.

Entity Framework i odwołania

Domyślnie Entity Framework jest uwzględniana podczas tworzenia nowej aplikacji sieci web ASP.NET przy użyciu szablonu formularzy sieci Web . Entity Framework można instalować, odinstalowywać i aktualizować jako pakiet NuGet.

Ten pakiet NuGet obejmuje następujące zestawy środowiska uruchomieniowego w ramach projektu:

  • EntityFramework. dll — wszystkie typowe kody środowiska uruchomieniowego używane przez Entity Framework
  • EntityFramework. SqlServer. dll — dostawca Microsoft SQL Server dla Entity Framework

Klasy jednostek

Klasy tworzone w celu zdefiniowania schematu danych są nazywane klasami jednostek. Jeśli dopiero zaczynasz Projektowanie bazy danych, pomyśl o klasach jednostek jako definicje tabel bazy danych. Każda właściwość w klasie Określa kolumnę w tabeli bazy danych. Klasy te zapewniają uproszczony, relacyjny interfejs między kodem zorientowanym na obiekt i strukturą tabeli relacyjnej bazy danych.

W tym samouczku rozpocznie się dodawanie prostych klas jednostek reprezentujących schematy dla produktów i kategorii. Klasa Products zawiera definicje dla każdego produktu. Nazwa każdego z elementów członkowskich klasy Product będzie ProductID, ProductName, Description, ImagePath, UnitPrice, CategoryIDi Category. Klasa kategorii będzie zawierać definicje dla każdej kategorii, do której może należeć produkt, np. samochodu, łodzi lub płaszczyzny. Nazwa każdego z elementów członkowskich klasy kategorii będzie CategoryID, CategoryName, Descriptioni Products. Każdy produkt należy do jednej z kategorii. Te klasy jednostek zostaną dodane do folderu istniejące modele projektu.

  1. W Eksplorator rozwiązańkliknij prawym przyciskiem myszy folder modele , a następnie wybierz pozycję Dodaj -> nowy element.

    Tworzenie warstwy dostępu do danych — menu nowy element

    Zostanie wyświetlone okno dialogowe Dodaj nowy element .

  2. W obszarze C# Wizualizacja z zainstalowanego okienka po lewej stronie wybierz pozycję kod.

    Tworzenie warstwy dostępu do danych — menu nowy element

  3. Wybierz pozycję Klasa w środkowym okienku i nadaj jej nazwę Product.cs.

  4. Kliknij pozycję Add (Dodaj).
    Nowy plik klasy zostanie wyświetlony w edytorze.

  5. Zastąp domyślny kod następującym kodem:

    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. Utwórz inną klasę przez powtórzenie kroków od 1 do 4, jednak Nadaj nazwę nowej klasie Category.cs i Zastąp kod domyślny następującym kodem:

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

Jak wspomniano wcześniej, Klasa Category reprezentuje typ produktu, który ma być sprzedawany przez aplikację (np. "samochodów", "łodzi", "rakiet", i tak dalej), a Klasa Product reprezentuje poszczególne produkty (zabawki) w bazie danych. Każde wystąpienie obiektu Product będzie odpowiadać wierszowi w tabeli relacyjnej bazy danych, a każda właściwość klasy Product zostanie zamapowana na kolumnę w tabeli relacyjnej bazy danych. W dalszej części tego samouczka przejrzyjesz dane produktu zawarte w bazie danych programu.

Adnotacje danych

Być może zauważono, że niektórzy członkowie klas mają atrybuty określające szczegóły dotyczące elementu członkowskiego, takie jak [ScaffoldColumn(false)]. Są to Adnotacje danych. Atrybuty adnotacji danych opisują sposób sprawdzania poprawności danych wejściowych użytkownika dla tego elementu członkowskiego, określania jego formatowania i określania sposobu modelowania podczas tworzenia bazy danych.

Context — Klasa

Aby rozpocząć korzystanie z klas do uzyskiwania dostępu do danych, należy zdefiniować klasę kontekstową. Jak wspomniano wcześniej, Klasa kontekstu zarządza klasami jednostek (takimi jak Klasa Product i Klasa Category) i zapewnia dostęp do danych w bazie danych.

Ta procedura powoduje dodanie nowej C# klasy kontekstu do folderu models .

  1. Kliknij prawym przyciskiem myszy folder modele , a następnie wybierz pozycję Dodaj -> nowy element.
    Zostanie wyświetlone okno dialogowe Dodaj nowy element .

  2. Wybierz pozycję Klasa w środkowym okienku, nadaj jej nazwę ProductContext.cs i kliknij przycisk Dodaj.

  3. Zastąp domyślny kod zawarty w klasie następującym kodem:

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

Ten kod dodaje System.Data.Entity przestrzeń nazw, dzięki czemu masz dostęp do wszystkich podstawowych funkcji Entity Framework, które obejmują możliwość wykonywania zapytań, wstawiania, aktualizowania i usuwania danych przez pracę z silnie określonymi obiektami.

Klasa ProductContext reprezentuje kontekst bazy danych produktu Entity Framework, który obsługuje pobieranie, przechowywanie i aktualizowanie wystąpień klasy Product w bazie danych. Klasa ProductContext pochodzi od klasy bazowej DbContext dostarczonej przez Entity Framework.

Klasa inicjatora

Musisz uruchomić pewną logikę niestandardową, aby zainicjować bazę danych przy pierwszym użyciu kontekstu. Pozwoli to na dodanie danych inicjatora do bazy danych, dzięki czemu można natychmiast wyświetlić produkty i kategorie.

Ta procedura powoduje dodanie nowej C# klasy inicjatora do folderu models .

  1. Utwórz kolejną Class w folderze modele i nadaj jej nazwę ProductDatabaseInitializer.cs.

  2. Zastąp domyślny kod zawarty w klasie następującym kodem:

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

Jak widać w powyższym kodzie, po utworzeniu i zainicjowaniu bazy danych Właściwość Seed zostanie zastąpiona i ustawiona. Po ustawieniu właściwości Seed, wartości z kategorii i produktów są używane do wypełniania bazy danych. Jeśli spróbujesz zaktualizować dane inicjatora, modyfikując powyższy kod po utworzeniu bazy danych, podczas uruchamiania aplikacji sieci Web nie będą wyświetlane żadne aktualizacje. Przyczyną jest użycie w powyższym kodzie implementacji klasy DropCreateDatabaseIfModelChanges, aby rozpoznać, czy model (schemat) został zmieniony przed zresetowaniem danych inicjatora. Jeśli nie wprowadzono żadnych zmian do Category i Product klas jednostek, baza danych nie zostanie zainicjowana ponownie przy użyciu danych inicjatora.

Note

Jeśli chcesz, aby baza danych była ponownie tworzona przy każdym uruchomieniu aplikacji, można użyć klasy DropCreateDatabaseAlways zamiast klasy DropCreateDatabaseIfModelChanges. Jednak w tej serii samouczków należy użyć klasy DropCreateDatabaseIfModelChanges.

W tym punkcie w tym samouczku będziesz mieć folder modele z czterema nowymi klasami i jedną domyślną klasą:

Tworzenie folderu modele warstwy dostępu do danych

Konfigurowanie aplikacji do korzystania z modelu danych

Teraz, po utworzeniu klas, które reprezentują dane, musisz skonfigurować aplikację tak, aby korzystała z klas. W pliku Global. asax należy dodać kod, który inicjuje model. W pliku Web. config dodawane są informacje informujące aplikację, która baza danych ma być używana do przechowywania danych reprezentowanych przez nowe klasy danych. Plik Global. asax może służyć do obsługi zdarzeń lub metod aplikacji. Plik Web. config pozwala kontrolować konfigurację aplikacji sieci Web ASP.NET.

Aktualizowanie pliku Global. asax

Aby zainicjować modele danych podczas uruchamiania aplikacji, należy zaktualizować procedurę obsługi Application_Start w pliku Global.asax.cs .

Note

W Eksplorator rozwiązań można wybrać plik Global. asax lub plik Global.asax.cs , aby edytować plik Global.asax.cs .

  1. Dodaj następujący kod wyróżniony kolorem żółtym do metody Application_Start w pliku 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());
            }
        }
    }
    

Note

Przeglądarka musi obsługiwać kod wyróżniony przy użyciu języka HTML5 podczas wyświetlania tej serii samouczków w przeglądarce.

Jak pokazano w powyższym kodzie, gdy aplikacja zostanie uruchomiona, aplikacja określa inicjator, który zostanie uruchomiony podczas pierwszego dostępu do danych. Do uzyskania dostępu do obiektu Database i obiektu ProductDatabaseInitializer są wymagane dwa dodatkowe przestrzenie nazw.

Modyfikowanie pliku Web. config

Mimo że usługa Entity Framework Code First wygeneruje bazę danych dla Ciebie w domyślnej lokalizacji, gdy baza danych zostanie wypełniona danymi o inicjatorze, dodanie własnych informacji o połączeniu do aplikacji zapewnia kontrolę nad lokalizacją bazy danych. To połączenie z bazą danych należy określić przy użyciu parametrów połączenia w pliku Web. config aplikacji w katalogu głównym projektu. Dodając nowe parametry połączenia, można skierować lokalizację bazy danych (wingtiptoys. mdf) do skompilowania w katalogu danych aplikacji ( _danych aplikacji), a nie w domyślnej lokalizacji. Wprowadzenie tej zmiany umożliwi znalezienie i inspekcję pliku bazy danych w dalszej części tego samouczka.

  1. W Eksplorator rozwiązańZnajdź i Otwórz plik Web. config .

  2. Dodaj parametry połączenia wyróżnione kolorem żółtym do sekcji <connectionStrings> w pliku Web. config w następujący sposób:

    <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;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)\v11.0;AttachDbFilename=|DataDirectory|\wingtiptoys.mdf;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    </connectionStrings>
    

Gdy aplikacja jest uruchamiana po raz pierwszy, spowoduje skompilowanie bazy danych w lokalizacji określonej przez parametry połączenia. Ale przed uruchomieniem aplikacji Utwórzmy ją w pierwszej kolejności.

Kompilowanie aplikacji

Aby upewnić się, że wszystkie klasy i zmiany w aplikacji sieci Web działają, należy skompilować aplikację.

  1. Z menu Debuguj wybierz polecenie Build WingtipToys.
    Zostanie wyświetlone okno dane wyjściowe , a jeśli wszystko zostało prawidłowo wykonane , zobaczysz komunikat o błędzie.

    Tworzenie warstwy dostępu do danych — okna danych wyjściowych

Jeśli wystąpi błąd, ponownie sprawdź powyższe kroki. Informacje w oknie danych wyjściowych wskazują, który plik ma problem i gdzie w pliku jest wymagana zmiana. Te informacje umożliwią określenie, jakie części powyższych kroków należy przejrzeć i naprawić w projekcie.

Podsumowanie

W tym samouczku dla serii, w której utworzono model danych, a także dodano kod, który będzie używany do inicjowania i wypełniania bazy danych. Aplikacja została również skonfigurowana do korzystania z modeli danych podczas uruchamiania aplikacji.

W następnym samouczku należy zaktualizować interfejs użytkownika, dodać nawigację i pobrać dane z bazy danych. Spowoduje to, że baza danych zostanie automatycznie utworzona na podstawie klas jednostek utworzonych w tym samouczku.

Dodatkowe materiały

Entity Framework przegląd
Przewodnik początkującego ADO.NET Entity Framework
Programowanie Code First przy użyciu Entity Framework (wideo)
Code First relacje między interfejsem API Fluent
Code First adnotacje danych
Ulepszenia produktywności Entity Framework