Поделиться через


Создание модели данных Entity Framework для приложения MVC ASP.NET (1 из 10)

Том Дайкстра

Примечание.

Новая версия этого руководства доступна для Visual Studio 2013, Entity Framework 6 и MVC 5.

Пример веб-приложения Contoso University демонстрирует создание ASP.NET приложений MVC 4 с помощью Entity Framework 5 и Visual Studio 2012. В этом примере приложения реализуется веб-сайт вымышленного университета Contoso. На нем предусмотрены различные функции, в том числе прием учащихся, создание курсов и назначение преподавателей. В этом руководстве объясняется, как создать пример приложения Contoso University.

Code First

Существует три способа работы с данными в Entity Framework: База данных First, Model First и Code First. Это руководство предназначено для code First. Сведения о различиях между этими рабочими процессами и рекомендациями по выбору лучшего для вашего сценария см. в разделе "Рабочие процессы разработки Entity Framework".

MVC

Пример приложения основан на ASP.NET MVC. Если вы предпочитаете работать с моделью ASP.NET веб-формы, см. серию руководств по привязке модели и веб-формы и ASP.NET карте содержимого доступа к данным.

Версии программного обеспечения

Показан в руководстве Также работает с
Windows 8 Windows 7
Visual Studio 2012 Visual Studio 2012 Express для Интернета. Это автоматически устанавливается пакетом SDK для Windows Azure, если у вас еще нет VS 2012 или VS 2012 Express для Интернета. Visual Studio 2013 должна работать, но руководство не было проверено с ним, а некоторые пункты меню и диалоговые окна отличаются. Для развертывания Windows Azure требуется версия ПАКЕТА SDK Для Windows Azure в VS 2013.
.NET 4.5 Большинство отображаемых функций будут работать в .NET 4, но некоторые из них не будут. Например, для поддержки перечисления в EF требуется .NET 4.5.
Entity Framework 5
Пакет SDK для Windows Azure 2.1 Если пропустить шаги развертывания Windows Azure, вам не нужен пакет SDK. При выпуске новой версии пакета SDK ссылка установит более новую версию. В этом случае может потребоваться адаптировать некоторые инструкции к новому пользовательскому интерфейсу и функциям.

Вопросы

Если у вас есть вопросы, которые не связаны напрямую с руководством, их можно опубликовать на форуме ASP.NET Entity Framework, форуме Entity Framework и LINQ to Entity Entity, или StackOverflow.com.

Благодарности

См. последнее руководство в серии для подтверждения и примечание о VB.

Веб-приложение Университета Contoso

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

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

Students_Index_page

Снимок экрана, показывающий пример страницы поиска учащихся в Университете Contoso и страницу создания нового учащегося.

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

Необходимые компоненты

Инструкции и снимки экрана в этом руководстве предполагают, что вы используете Visual Studio 2012 или Visual Studio 2012 Express для Интернета с последним обновлением и пакетом SDK Azure для .NET, установленным по состоянию на июль 2013 года. Все это можно получить со следующей ссылкой:

Пакет SDK Azure для .NET (Visual Studio 2012)

Если вы установили Visual Studio, ссылка выше установит отсутствующие компоненты. Если у вас нет Visual Studio, ссылка установит Visual Studio 2012 Express для Интернета. Вы можете использовать Visual Studio 2013, но некоторые из обязательных процедур и экранов будут отличаться.

Создание веб-приложения MVC

Откройте Visual Studio и создайте проект C# с именем ContosoUniversity с помощью шаблона веб-приложения MVC 4 ASP.NET. Убедитесь, что вы нацелены на платформа .NET Framework 4.5 (вы будете использовать enum свойства и требуется .NET 4.5).

New_project_dialog_box

В диалоговом окне "Новый ASP.NET проект MVC 4" выберите шаблон приложения Интернета.

Оставьте выбранный обработчик представлений Razor и оставьте флажок "Создать модульный тестовый проект ".

Щелкните OK.

Project_template_options

Настройка стиля сайта

Выполните незначительную настройку меню, макета и домашней страницы сайта.

Откройте views\Shared\_Layout.cshtml и замените содержимое файла следующим кодом. Изменения выделены.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - Contoso University</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")
    </head>
    <body>
        <header>
            <div class="content-wrapper">
                <div class="float-left">
                    <p class="site-title">@Html.ActionLink("Contoso University", "Index", "Home")</p>
                </div>
                <div class="float-right">
                    <section id="login">
                        @Html.Partial("_LoginPartial")
                    </section>
                    <nav>
                        <ul id="menu">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("About", "About", "Home")</li>
                            <li>@Html.ActionLink("Students", "Index", "Student")</li>
                            <li>@Html.ActionLink("Courses", "Index", "Course")</li>
                            <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li>
                            <li>@Html.ActionLink("Departments", "Index", "Department")</li>
                        </ul>
                    </nav>
                </div>
            </div>
        </header>
        <div id="body">
            @RenderSection("featured", required: false)
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>
        <footer>
            <div class="content-wrapper">
                <div class="float-left">
                    <p>&copy; @DateTime.Now.Year - Contoso University</p>
                </div>
            </div>
        </footer>

        @Scripts.Render("~/bundles/jquery")
        @RenderSection("scripts", required: false)
    </body>
</html>

Этот код вносит следующие изменения.

  • Заменяет экземпляры шаблона "My ASP.NET MVC Application" и "Your logo here" на Contoso University.
  • Добавляет несколько ссылок действий, которые будут использоваться далее в руководстве.

В Представлениях\Home\Index.cshtml замените содержимое файла следующим кодом, чтобы исключить абзацы шаблона о ASP.NET и MVC:

@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>
        </div>
    </section>
}

В Controllers\HomeController.cs измените значение ViewBag.Message в Index методе Action на "Добро пожаловать в Университет Contoso!", как показано в следующем примере:

public ActionResult Index()
{
    ViewBag.Message = "Welcome to Contoso University";

    return View();
}

Нажмите клавиши CTRL+F5, чтобы запустить сайт. Вы увидите домашнюю страницу с главной меню.

Contoso_University_home_page

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

Теперь необходимо создать классы сущностей для приложения университета Contoso. Начните с следующих трех сущностей:

Class_diagram

Между сущностями Student и Enrollment, а также между сущностями Course и Enrollment существует отношение "один ко многим". Другими словами, учащийся может быть зарегистрирован в любом количестве курсов, а в отдельном курсе может быть зарегистрировано любое количество учащихся.

В следующих разделах создаются классы для каждой из этих сущностей.

Примечание.

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

Сущность учащегося

Student_entity

В папке "Модели" создайте Student.cs и замените существующий код следующим кодом:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int StudentID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

Свойство StudentID будет использоваться в качестве столбца первичного ключа в таблице базы данных, соответствующей этому классу. По умолчанию Entity Framework интерпретирует свойство, которое называется или имя ID ID класса в качестве первичного ключа.

Свойство Enrollments является свойством навигации. Свойства навигации содержат другие сущности, связанные с этой сущностью. В этом случае Enrollments свойство сущности Student будет содержать все Enrollment сущности, связанные с этой Student сущностью. Другими словами, если в Student базе данных есть две связанные Enrollment строки (строки, содержащие значение первичного ключа учащегося в столбце StudentID внешнего ключа), то Student свойство навигации сущности Enrollments будет содержать эти две Enrollment сущности.

Свойства навигации обычно определяются так virtual , чтобы они могли воспользоваться некоторыми функциями Entity Framework, такими как отложенная загрузка. (Отложенная загрузка будет описана позже, в Чтение учебника по связанным данным далее в этой серии.

Если свойство навигации может содержать несколько сущностей (как в отношениях "многие ко многим" или "один ко многим"), оно должно иметь тип списка, допускающий добавление, удаление и обновление записей, такой как ICollection.

Сущность регистрации

Enrollment_entity

В папке Models создайте файл Enrollment.cs и замените существующий код следующим кодом:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }
        
        public virtual Course Course { get; set; }
        public virtual Student Student { get; set; }
    }
}

Свойство Grade является перечислением. Знак вопроса после объявления типа Grade указывает, что свойство Gradeдопускает значение NULL. Класс, который имеет значение NULL, отличается от нулевого класса— значение NULL означает, что оценка еще не известна или не назначена.

Свойство StudentID представляет собой внешний ключ. Ему соответствует свойство навигации Student. Сущность Enrollment связана с одной сущностью Student, поэтому это свойство может содержать одну сущность Student (в отличие от представленного ранее свойства навигации Student.Enrollments, которое может содержать несколько сущностей Enrollment).

Свойство CourseID представляет собой внешний ключ. Ему соответствует свойство навигации Course. Сущность Enrollment связана с одной сущностью Course.

Сущность Course

Course_entity

В папке Models создайте Course.cs, заменив существующий код следующим кодом:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }
        
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
}

Свойство Enrollments является свойством навигации. Сущность Course может быть связана с любым числом сущностей Enrollment.

Мы поговорим больше о [DatabaseGenerated(DatabaseGeneratedOption). Нет)] атрибут в следующем руководстве. Фактически, этот атрибут позволяет ввести первичный ключ для курса, а не использовать базу данных, чтобы создать его.

Создание контекста базы данных

Основной класс, который координирует функциональные возможности Entity Framework для данной модели данных, — это класс контекста базы данных. Этот класс создается путем извлечения из класса System.Data.Entity.DbContext . В коде указываются сущности, которые включаются в модель данных. Также вы можете настроить реакцию платформы Entity Framework на некоторые события. В этом проекте соответствующий класс называется SchoolContext.

Создайте папку с именем DAL (для уровня доступа к данным). В этой папке создайте файл класса с именем SchoolContext.cs и замените существующий код следующим кодом:

using ContosoUniversity.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ContosoUniversity.DAL
{
    public class SchoolContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }
}

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

Инструкция в методе modelBuilder.Conventions.Remove OnModelCreating предотвращает плюрализацию имен таблиц. Если вы этого не сделали, созданные таблицы будут называться Students, Coursesи Enrollments. Вместо этого имена таблиц будут Studentиметь значение , Courseи Enrollment. В среде разработчиков нет единого мнения о том, следует ли использовать имена таблиц во множественном числе. В этом руководстве используется единственная форма, но важно выбрать любую форму, которую вы предпочитаете, включив или опустив эту строку кода.

SQL Server Express LocalDB

LocalDB — это упрощенная версия SQL Server Express ядро СУБД, которая запускается по запросу и выполняется в пользовательском режиме. LocalDB выполняется в специальном режиме выполнения SQL Server Express, который позволяет работать с базами данных в виде .mdf файлов. Как правило, файлы базы данных LocalDB хранятся в папке App_Data веб-проекта. Функция экземпляра пользователя в SQL Server Express также позволяет работать с .mdf файлами, но функция экземпляра пользователя устарела. Поэтому для работы с файлами .mdf рекомендуется использовать LocalDB.

Обычно SQL Server Express не используется для рабочих веб-приложений. В частности, localDB не рекомендуется использовать в рабочей среде с веб-приложением, так как он не предназначен для работы с IIS.

В Visual Studio 2012 и более поздних версиях LocalDB устанавливается по умолчанию с Помощью Visual Studio. В Visual Studio 2010 и более ранних версиях SQL Server Express (без LocalDB) устанавливается по умолчанию с Помощью Visual Studio; Его необходимо установить вручную, если вы используете Visual Studio 2010.

В этом руководстве вы будете работать с LocalDB, чтобы база данных была сохранена в папке App_Data в виде файла .mdf. Откройте корневой файл web.config и добавьте новый строка подключения в коллекциюconnectionStrings, как показано в следующем примере. (Убедитесь, что вы обновляете Файл Web.config в корневой папке проекта. Файл конфигурации Web.config также находится в вложенной папке Views, которую не нужно обновлять.)

<add name="SchoolContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\ContosoUniversity.mdf" providerName="System.Data.SqlClient" />

По умолчанию Entity Framework ищет строка подключения с именем DbContext класса (SchoolContextдля этого проекта). Добавленная строка подключения указывает базу данных LocalDB с именем ContosoUniversity.mdf, расположенную в папке App_Data. Дополнительные сведения см. в разделе "Строки подключения SQL Server" для веб-приложений ASP.NET.

На самом деле вам не нужно указывать строка подключения. Если вы не предоставляете строка подключения, Entity Framework создаст ее для вас. Однако база данных может не находиться в папке App_data приложения. Сведения о том, где будет создана база данных, см. в разделе Code First to a New Database.

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

Настройка и выполнение первой миграции кода

При первом запуске разработки приложения модель данных часто изменяется, и каждый раз, когда модель изменяет ее, выходит из синхронизации с базой данных. Вы можете настроить Entity Framework для автоматического удаления и повторного создания базы данных при каждом изменении модели данных. Это не проблема в начале разработки, так как тестовые данные легко создаются повторно, но после развертывания в рабочей среде обычно требуется обновить схему базы данных без удаления базы данных. Функция "Миграции" позволяет коду сначала обновлять базу данных без удаления и повторного ее создания. В начале цикла разработки нового проекта может потребоваться использовать DropCreateDatabaseIfModelChanges для удаления, повторного создания и повторного заполнения базы данных при каждом изменении модели. Вы можете подготовиться к развертыванию приложения, который можно преобразовать в подход миграции. В этом руководстве вы будете использовать только миграции. Дополнительные сведения см. в разделе "Code First Migrations and Migrations Screencast Series".

Включение Code First Migrations

  1. В меню Сервис щелкните Диспетчер пакетов NuGet, а затем щелкните Консоль диспетчера пакетов.

    Selecting_Package_Manager_Console

  2. В командной строке PM> введите следующую команду:

    enable-migrations -contexttypename SchoolContext
    

    Команда enable-migrations

    Эта команда создает папку Migrations в проекте ContosoUniversity и помещает в нее файл Configuration.cs , который можно изменить для настройки миграций.

    Папка миграции

    Класс Configuration включает Seed метод, который вызывается при создании базы данных и при каждом обновлении после изменения модели данных.

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.Models.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.Models.SchoolContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
    

    Этот Seed метод предназначен для вставки тестовых данных в базу данных после создания или обновления кода.

Настройка метода "Начальное значение"

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

В более ранних версиях Кода First перед выпуском миграции часто используются Seed методы для вставки тестовых данных, так как при каждом изменении модели во время разработки база данных должна быть полностью удалена и повторно создана с нуля. При первой миграции кода тестовые данные сохраняются после изменений базы данных, поэтому, как правило, не требуется тестовые данные в методе Seed . На самом деле вы не хотите Seed , чтобы метод вставлял тестовые данные, если вы будете использовать миграции для развертывания базы данных в рабочую среду, так как Seed этот метод будет выполняться в рабочей среде. В этом случае необходимо Seed , чтобы метод вставлялся в базу данных только те данные, которые необходимо вставить в рабочую среду. Например, может потребоваться, чтобы база данных включала фактические имена отделов в Department таблицу, когда приложение становится доступным в рабочей среде.

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

  1. Замените содержимое файла Configuration.cs следующим кодом, который нагрузит данные нагрузочного теста в новую базу данных.

    namespace ContosoUniversity.Migrations
    {
       using System;
       using System.Collections.Generic;
       using System.Data.Entity.Migrations;
       using System.Linq;
       using ContosoUniversity.Models;
    
       internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
       {
          public Configuration()
          {
             AutomaticMigrationsEnabled = false;
          }
    
          protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
          {
             var students = new List<Student>
                {
                    new Student { FirstMidName = "Carson",   LastName = "Alexander", 
                        EnrollmentDate = DateTime.Parse("2010-09-01") },
                    new Student { FirstMidName = "Meredith", LastName = "Alonso",    
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Arturo",   LastName = "Anand",     
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Gytis",    LastName = "Barzdukas", 
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Yan",      LastName = "Li",        
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Peggy",    LastName = "Justice",   
                        EnrollmentDate = DateTime.Parse("2011-09-01") },
                    new Student { FirstMidName = "Laura",    LastName = "Norman",    
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Nino",     LastName = "Olivetto",  
                        EnrollmentDate = DateTime.Parse("2005-08-11") }
                };
             students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
             context.SaveChanges();
    
             var courses = new List<Course>
                {
                    new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3, },
                    new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
                    new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
                    new Course {CourseID = 1045, Title = "Calculus",       Credits = 4, },
                    new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4, },
                    new Course {CourseID = 2021, Title = "Composition",    Credits = 3, },
                    new Course {CourseID = 2042, Title = "Literature",     Credits = 4, }
                };
             courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
             context.SaveChanges();
    
             var enrollments = new List<Enrollment>
                {
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").StudentID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").StudentID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").StudentID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").StudentID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
             foreach (Enrollment e in enrollments)
             {
                var enrollmentInDataBase = context.Enrollments.Where(
                    s =>
                         s.Student.StudentID == e.StudentID &&
                         s.Course.CourseID == e.CourseID).SingleOrDefault();
                if (enrollmentInDataBase == null)
                {
                   context.Enrollments.Add(e);
                }
             }
             context.SaveChanges();
          }
       }
    }
    

    Метод Seed принимает объект контекста базы данных в качестве входного параметра, а код в методе использует этот объект для добавления новых сущностей в базу данных. Для каждого типа сущности код создает коллекцию новых сущностей, добавляет их в соответствующее свойство DbSet , а затем сохраняет изменения в базе данных. Не обязательно вызывать метод SaveChanges после каждой группы сущностей, как показано здесь, но это помогает найти источник проблемы, если исключение возникает во время записи кода в базу данных.

    Некоторые инструкции, вставляемые данные, используют метод AddOrUpdate для выполнения операции upsert. Seed Так как метод выполняется с каждой миграцией, вы не можете просто вставить данные, так как строки, которые вы пытаетесь добавить, уже будут там после первой миграции, которая создает базу данных. Операция upsert предотвращает ошибки, которые будут возникать при попытке вставить строку, которая уже существует, но переопределяет любые изменения данных, которые, возможно, были сделаны при тестировании приложения. С тестируемыми данными в некоторых таблицах может не потребоваться это сделать: в некоторых случаях при изменении данных при тестировании изменения будут оставаться после обновления базы данных. В этом случае необходимо выполнить условную операцию вставки: вставить строку только в том случае, если она еще не существует. Метод Seed использует оба подхода.

    Первый параметр, переданный методу AddOrUpdate , указывает свойство, используемое для проверки наличия строки. Для данных тестового учащегося, которое вы предоставляете, свойство можно использовать для этой цели, LastName так как каждое фамилию в списке уникально:

    context.Students.AddOrUpdate(p => p.LastName, s)
    

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

    Последовательность содержит несколько элементов

    Дополнительные сведения о методе AddOrUpdate см. в блоге Ef 4.3 AddOrUpdate в блоге Джули Лермана.

    Код, добавляющий Enrollment сущности, не использует AddOrUpdate метод. Он проверяет, существует ли сущность и вставляет сущность, если она не существует. Этот подход сохранит изменения, внесенные в оценку регистрации при выполнении миграции. Код циклит по каждому элементу Enrollmentсписка и если регистрация не найдена в базе данных, она добавляет регистрацию в базу данных. При первом обновлении базы данных база данных будет пуста, поэтому она добавит каждую регистрацию.

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.StudentID == e.Student.StudentID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    

    Сведения о отладке метода и обработке Seed избыточных данных, таких как два учащихся с именем "Александр Карсон", см. в блоге Rick Anderson.

  2. Выполните сборку проекта.

Создание и выполнение первой миграции

  1. В окне консоли диспетчер пакетов введите следующие команды:

    add-migration InitialCreate
    update-database
    

    Снимок экрана: окно консоли диспетчер пакетов. Команды добавляют перенос дефиса подчеркивания начального создания и обновления базы данных дефиса.

    Команда add-migration добавляется в папку Migrations файл [DateStamp]_InitialCreate.cs , содержащий код, который создает базу данных. Первый параметр (InitialCreate) используется для имени файла и может быть любым, что вы хотите; обычно вы выбираете слово или фразу, которая суммирует то, что делается в миграции. Например, последнюю миграцию можно назвать "AddDepartmentTable".

    Папка миграции с начальной миграцией

    Метод Up InitialCreate класса создает таблицы базы данных, соответствующие наборам сущностей модели данных, и Down метод удаляет их. Функция миграций вызывает метод Up, чтобы реализовать изменения модели данных для миграции. При вводе команды для отката обновления функция миграций вызывает метод Down. В следующем коде показано содержимое InitialCreate файла:

    namespace ContosoUniversity.Migrations
    {
        using System;
        using System.Data.Entity.Migrations;
        
        public partial class InitialCreate : DbMigration
        {
            public override void Up()
            {
                CreateTable(
                    "dbo.Student",
                    c => new
                        {
                            StudentID = c.Int(nullable: false, identity: true),
                            LastName = c.String(),
                            FirstMidName = c.String(),
                            EnrollmentDate = c.DateTime(nullable: false),
                        })
                    .PrimaryKey(t => t.StudentID);
                
                CreateTable(
                    "dbo.Enrollment",
                    c => new
                        {
                            EnrollmentID = c.Int(nullable: false, identity: true),
                            CourseID = c.Int(nullable: false),
                            StudentID = c.Int(nullable: false),
                            Grade = c.Int(),
                        })
                    .PrimaryKey(t => t.EnrollmentID)
                    .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
                    .ForeignKey("dbo.Student", t => t.StudentID, cascadeDelete: true)
                    .Index(t => t.CourseID)
                    .Index(t => t.StudentID);
                
                CreateTable(
                    "dbo.Course",
                    c => new
                        {
                            CourseID = c.Int(nullable: false),
                            Title = c.String(),
                            Credits = c.Int(nullable: false),
                        })
                    .PrimaryKey(t => t.CourseID);
                
            }
            
            public override void Down()
            {
                DropIndex("dbo.Enrollment", new[] { "StudentID" });
                DropIndex("dbo.Enrollment", new[] { "CourseID" });
                DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
                DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
                DropTable("dbo.Course");
                DropTable("dbo.Enrollment");
                DropTable("dbo.Student");
            }
        }
    }
    

    Команда update-database запускает Up метод для создания базы данных, а затем запускает Seed метод для заполнения базы данных.

База данных SQL Server теперь создана для модели данных. Имя базы данных — ContosoUniversity, а файл .mdf находится в папке App_Data проекта, так как это то, что вы указали в строка подключения.

Обозреватель сервера или SQL Server обозреватель объектов (SSOX) можно использовать для просмотра базы данных в Visual Studio. В этом руководстве вы будете использовать обозреватель серверов. В Visual Studio Express 2012 для Интернета обозреватель серверов называется Database Explorer.

  1. В меню "Вид " щелкните обозреватель серверов.

  2. Щелкните значок "Добавить подключение".

    Снимок экрана: окно обозревателя баз данных. Выделен значок добавления подключения.

  3. Если появится запрос в диалоговом окне выбора источника данных, щелкните Microsoft SQL Server и нажмите кнопку "Продолжить".

    Снимок экрана: диалоговое окно

  4. В диалоговом окне "Добавление подключения" введите (localdb)\v11.0 для имени сервера. В разделе "Выбор" или введите имя базы данных, выберите ContosoUniversity.

    Снимок экрана: диалоговое окно

  5. Щелкните OK.

  6. Разверните SchoolContext и разверните таблицы.

    Снимок экрана: страница обозревателя серверов. Развернуты вкладки

  7. Щелкните правой кнопкой мыши таблицу Student и щелкните "Показать данные таблицы", чтобы просмотреть созданные столбцы и строки, вставленные в таблицу.

    Таблица учащихся

Создание контроллера учащихся и представлений

Следующим шагом является создание контроллера и представлений MVC ASP.NET в приложении, которые могут работать с одной из этих таблиц.

  1. Чтобы создать контроллер, щелкните правой Student кнопкой мыши папку "Контроллеры" в Обозреватель решений, выберите "Добавить" и нажмите кнопку "Контроллер". В диалоговом окне "Добавить контроллер" выберите следующие элементы и нажмите кнопку "Добавить".

    • Имя контроллера: StudentController.

    • Шаблон: контроллер MVC с действиями и представлениями чтения и записи с помощью Entity Framework.

    • Класс модели: Student (ContosoUniversity.Models). (Если этот параметр не отображается в раскрывающемся списке, создайте проект и повторите попытку.)

    • Класс контекста данных: SchoolContext (ContosoUniversity.Models).

    • Представления: Razor (CSHTML). (Значение по умолчанию.)

      Add_Controller_dialog_box_for_Student_controller

  2. Visual Studio открывает файл Controllers\StudentController.cs . Вы видите, что переменная класса создана, которая создает экземпляр объекта контекста базы данных:

    private SchoolContext db = new SchoolContext();
    

    Метод Index действия получает список учащихся из сущности "Учащиеся ", считывая Students свойство экземпляра контекста базы данных:

    public ViewResult Index()
    {
        return View(db.Students.ToList());
    }
    

    Представление Student\Index.cshtml отображает этот список в таблице:

    <table>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.FirstMidName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </th>
            <th></th>
        </tr>
    
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
                @Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
            </td>
        </tr>
    }
    
  3. Нажмите клавиши CTRL+F5, чтобы запустить проект.

    Перейдите на вкладку "Учащиеся " , чтобы просмотреть тестовые данные, вставленные методом Seed .

    Страница индекса учащихся

Соглашения

Объем кода, который необходимо написать, чтобы Entity Framework мог создать полную базу данных для вас минимально из-за использования соглашений или предположений, которые делает Entity Framework. Некоторые из них уже отмечены:

  • В качестве имен таблиц используются плюрализованные формы имен классов сущностей.
  • В качестве имен столбцов используются имена свойств сущностей.
  • Свойства сущности, именованные ID или имена ID классов, распознаются как свойства первичного ключа.

Вы видели, что соглашения можно переопределить (например, вы указали, что имена таблиц не должны быть плюрализованы), и вы узнаете больше о соглашениях и о том, как переопределить их в руководстве по созданию более сложной модели данных далее в этом ряду. Дополнительные сведения см. в разделе "Code First Conventions".

Итоги

Теперь вы создали простое приложение, использующее Entity Framework и SQL Server Express для хранения и отображения данных. В следующем руководстве вы узнаете, как выполнять базовые операции CRUD (создание, чтение, обновление, удаление). Вы можете оставить отзыв в нижней части этой страницы. Сообщите нам, как вы любили эту часть учебника и как мы могли бы улучшить его.

Ссылки на другие ресурсы Entity Framework можно найти на карте содержимого доступа к данным ASP.NET.