Создание уровня доступа к данным

Эрик Рейтан

В этой серии руководств вы узнаете об основах создания приложения ASP.NET Web Forms с помощью ASP.NET 4.5 и Microsoft Visual Studio Express 2013 для Web. В рамках этой серии руководств доступен проект Visual Studio 2013 с исходным кодом C#.

В этом руководстве описывается, как создавать, просматривать и просматривать данные из базы данных с помощью ASP.NET Web Forms и Entity Framework Code First. Это руководство основывается на предыдущем руководстве "Создание проекта" и входит в серию учебников Wingtip Toy Store. По завершении работы с этим руководством вы получите группу классов доступа к данным, которые находятся в папке Models проекта.

Из этого руководства вы узнаете, как выполнять такие задачи:

  • Создание моделей данных.
  • Как инициализировать и заполнить базу данных.
  • Обновление и настройка приложения для поддержки базы данных.

В этом руководстве представлены следующие функции:

  • Entity Framework Code First
  • LocalDB
  • Заметки к данным

Создание моделей данных

Entity Framework — это платформа объектно-реляционного сопоставления (ORM). Он позволяет работать с реляционными данными как объектами, устраняя большую часть кода для доступа к данным, который обычно требуется писать. С помощью Entity Framework можно выполнять запросы с помощью LINQ, а затем извлекать данные как строго типизированные объекты и управлять ими. LINQ предоставляет шаблоны для запроса и обновления данных. Использование Entity Framework позволяет сосредоточиться на создании остальной части приложения, а не на основах доступа к данным. Далее в этой серии учебников мы покажем, как использовать данные для заполнения навигации и запросов к продуктам.

Entity Framework поддерживает парадигму разработки Под названием Code First. Code First позволяет определять модели данных с помощью классов. Класс — это конструкция, которая позволяет создавать собственные настраиваемые типы путем группирования переменных других типов, методов и событий. Классы можно сопоставить с существующей базой данных или использовать их для создания базы данных. В этом руководстве вы создадите модели данных, написав классы моделей данных. Затем вы разрешите Entity Framework создать базу данных на лету из этих новых классов.

Сначала вы создадите классы сущностей, которые определяют модели данных для приложения веб-формы. Затем вы создадите класс контекста, который управляет классами сущностей и предоставляет доступ к данным к базе данных. Вы также создадите класс инициализатора, который будет использоваться для заполнения базы данных.

Entity Framework и ссылки

По умолчанию Entity Framework включается при создании веб-приложения ASP.NET с помощью шаблона веб-формы. Entity Framework можно установить, удалить и обновить как пакет NuGet.

Этот пакет NuGet включает следующие сборки среды выполнения в проекте:

  • EntityFramework.dll — весь общий код среды выполнения, используемый Entity Framework.
  • EntityFramework.SqlServer.dll — поставщик microsoft SQL Server для Entity Framework

Классы сущностей

Классы, создаваемые для определения схемы данных, называются классами сущностей. Если вы не знакомы с проектированием баз данных, то классы сущностей можно рассматривать как табличные определения базы данных. Каждое свойство в классе задает столбец в таблице базы данных. Эти классы обеспечивают упрощенный объектно-реляционный интерфейс между объектно-ориентированным кодом и структурой реляционной таблицы базы данных.

В этом руководстве вы начнете с добавления простых классов сущностей, представляющих схемы для продуктов и категорий. Класс products будет содержать определения для каждого продукта. Имена каждого из членов класса продукта: ProductID, , ProductName, ImagePathDescription, , UnitPrice, CategoryID, и Category. Класс категорий будет содержать определения для каждой категории, к которой может принадлежать продукт, например Автомобиль, Лодка или Плоскость. Имя каждого из членов класса категории будет иметь следующие CategoryIDзначения: , CategoryName, Descriptionи Products. Каждый продукт будет относиться к одной из категорий. Эти классы сущностей будут добавлены в существующую папку Models проекта.

  1. В Обозреватель решений щелкните правой кнопкой мыши папку Models и выберите Добавить ->Новый элемент.

    Снимок экрана: окно Обозреватель решений с выделенной папкой Models и выбранными раскрывающимся меню Добавить и Новый элемент.

    Откроется диалоговое окно Добавление нового элемента.

  2. В разделе Visual C# в области Установленные слева выберите Код.

    Снимок экрана: окно

  3. Выберите Класс в средней области и назовите этот новый класс Product.cs.

  4. Нажмите кнопку Добавить.
    Новый файл класса отображается в редакторе.

  5. Замените код по умолчанию на приведенный ниже:

    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. Создайте другой класс, повторив шаги с 1 по 4, однако присвойте новому классу имя Category.cs и замените код по умолчанию следующим кодом:

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

Как упоминалось ранее, Category класс представляет тип продукта, который предназначен для продажи приложением (например , "Автомобили", "Лодки", "Ракеты" и т. д.), а Product класс представляет отдельные продукты (игрушки) в базе данных. Каждый экземпляр Product объекта будет соответствовать строке в таблице реляционной базы данных, а каждое свойство класса Product будет сопоставляться со столбцом в таблице реляционной базы данных. Далее в этом руководстве вы изучите данные о продукте, содержащиеся в базе данных.

Заметки к данным

Возможно, вы заметили, что некоторые члены классов имеют атрибуты, указывающие сведения об элементе, например [ScaffoldColumn(false)]. Это заметки к данным. Атрибуты заметки к данным могут описывать, как проверить введенные пользователем данные для этого элемента, указать форматирование для него и указать способ моделирования при создании базы данных.

Класс Context

Чтобы начать использовать классы для доступа к данным, необходимо определить класс контекста. Как упоминалось ранее, класс контекста управляет классами сущностей (например Product , классом и классом Category ) и предоставляет доступ к данным к базе данных.

Эта процедура добавляет новый класс контекста C# в папку Models .

  1. Щелкните правой кнопкой мыши папку Models и выберите Добавить ->Новый элемент.
    Откроется диалоговое окно Добавление нового элемента.

  2. Выберите Класс в средней области, назовите его ProductContext.cs и нажмите кнопку Добавить.

  3. Замените код по умолчанию, содержащийся в классе, следующим кодом:

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

Этот код добавляет System.Data.Entity пространство имен, чтобы у вас был доступ ко всем основным функциям Entity Framework, включая возможность запрашивать, вставлять, обновлять и удалять данные путем работы со строго типизированными объектами.

Класс ProductContext представляет контекст базы данных продукта Entity Framework, который обрабатывает получение, хранение и обновление Product экземпляров класса в базе данных. Класс ProductContext является производным от базового класса, предоставленного DbContext Entity Framework.

Класс инициализатора

Вам потребуется выполнить пользовательскую логику для инициализации базы данных при первом использовании контекста. Это позволит добавлять начальные данные в базу данных, чтобы вы могли сразу отображать продукты и категории.

Эта процедура добавляет новый класс инициализатора C# в папку Models .

  1. Создайте другой Class файл в папке Models и назовите его ProductDatabaseInitializer.cs.

  2. Замените код по умолчанию, содержащийся в классе, следующим кодом:

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

Как видно из приведенного выше кода, при создании и инициализации Seed базы данных свойство переопределяется и устанавливается. Seed Если свойство задано, для заполнения базы данных используются значения из категорий и продуктов. При попытке обновить начальные данные, изменив приведенный выше код после создания базы данных, вы не увидите никаких обновлений при запуске веб-приложения. Причина в том, что приведенный выше код использует реализацию DropCreateDatabaseIfModelChanges класса , чтобы распознать, изменилась ли модель (схема) перед сбросом начальных данных. Если в классы сущностей Category и Product не внесены изменения, база данных не будет повторно инициализирована с начальными данными.

Примечание

Если вы хотите, чтобы база данных создавалась повторно при каждом запуске приложения, можно использовать DropCreateDatabaseAlways класс вместо DropCreateDatabaseIfModelChanges класса . Однако для этой серии учебников используйте DropCreateDatabaseIfModelChanges класс .

На этом этапе в этом руководстве у вас будет папка Models с четырьмя новыми классами и одним классом по умолчанию:

Создание папки

Настройка приложения для использования модели данных

Теперь, когда вы создали классы, представляющие данные, необходимо настроить приложение для использования классов. В файл Global.asax добавьте код, который инициализирует модель. В файлWeb.config добавляются сведения, которые сообщают приложению, какую базу данных вы будете использовать для хранения данных, представленных новыми классами данных. Файл Global.asax можно использовать для обработки событий или методов приложения. Файл Web.config позволяет управлять конфигурацией веб-приложения ASP.NET.

Обновление файла Global.asax

Чтобы инициализировать модели данных при запуске приложения, необходимо обновить Application_Start обработчик в файле Global.asax.cs .

Примечание

В Обозреватель решений можно выбрать файл Global.asax или Global.asax.cs, чтобы изменить файл Global.asax.cs.

  1. Добавьте следующий код, выделенный желтым цветом, в Application_Start метод в файле 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());
            }
        }
    }
    

Примечание

Браузер должен поддерживать HTML5 для просмотра кода, выделенного желтым цветом при просмотре этой серии учебников в браузере.

Как показано в приведенном выше коде, при запуске приложения приложение указывает инициализатор, который будет выполняться при первом обращении к данным. Для доступа к объекту и объекту Database требуются два дополнительных ProductDatabaseInitializer пространства имен.

Изменение файла Web.Config

Хотя Entity Framework Code First создаст базу данных в расположении по умолчанию, когда база данных заполнена начальными данными, добавление собственных сведений о подключении к приложению позволяет управлять расположением базы данных. Это подключение к базе данных указывается с помощью строки подключения в файле Web.config приложения в корне проекта. Добавив новую строку подключения, можно указать расположение базы данных (wingtiptoys.mdf) для сборки в каталоге данных приложения (App_Data), а не в расположении по умолчанию. Внесение этого изменения позволит найти и изучить файл базы данных далее в этом руководстве.

  1. В Обозреватель решений найдите и откройте файлWeb.config.

  2. Добавьте строку подключения, выделенную желтым цветом, в <connectionStrings> раздел файлаWeb.config следующим образом:

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

При первом запуске приложение будет выполнять сборку базы данных в расположении, указанном в строке подключения. Но перед запуском приложения сначала создадим его.

Построение приложения

Чтобы убедиться, что все классы и изменения веб-приложения работают, необходимо создать приложение.

  1. В меню Отладка выберите Сборка WingtipToys.
    Откроется окно Вывод , и если все прошло успешно, появится сообщение об успешном выполнении .

    Создание уровня доступа к данным — окна вывода

При возникновении ошибки повторно проверка описанные выше действия. Сведения в окне Вывод указывают, в каком файле возникла проблема, и где в файле требуется изменение. Эти сведения помогут вам определить, какая часть описанных выше действий должна быть проверена и исправлена в проекте.

Итоги

В этом руководстве серии вы создали модель данных, а также добавили код, который будет использоваться для инициализации и заполнения базы данных. Вы также настроили приложение для использования моделей данных при запуске приложения.

В следующем руководстве вы обновите пользовательский интерфейс, добавите навигацию и получите данные из базы данных. Это приведет к автоматическому созданию базы данных на основе классов сущностей, созданных в этом руководстве.

Дополнительные ресурсы

Общие сведения об Entity Framework
Руководство для начинающих по ADO.NET Entity Framework
Code First Development with Entity FrameworkCode First Relationships Fluent API
Заметки к данным Code First
Повышение производительности для Entity Framework