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

от Tom Dykstra)

Note

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

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

Code First

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

MVC

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

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

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

Вопросы

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

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

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

Исходная версия учебника

Исходная версия учебника доступна в электронной книге EF 4,1/MVC 3.

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

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

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

Students_Index_page

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

Предварительные требования

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

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

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

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

Откройте Visual Studio и создайте новый проект C# с именем "ContosoUniversity" с помощью шаблона веб-приложения ASP.NET MVC 4 . Убедитесь, что вы используете платформа .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>

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

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

В Views\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 методе действия на "Добро пожаловать в 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 существует отношение "один ко многим". Другими словами, учащийся может быть зарегистрирован в любом количестве курсов, а в отдельном курсе может быть зарегистрировано любое количество учащихся.

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

Note

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

Сущность Student

Student_entity

В папке Models создайте 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 качестве первичного ключа свойство с именем или className 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.

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

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

Класс main, который координирует 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 хранятся в папке _ данных приложения веб-проекта. Функция пользовательского экземпляра в 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, чтобы базу данных можно было хранить в папке _ данных приложения в файле 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 , расположенную в папке _ данных приложения . Дополнительные сведения см. в разделе SQL Server строки подключения для веб-приложений ASP.NET.

В действительности нет необходимости указывать строку подключения. Если строка подключения не указана, Entity Framework создаст ее. Однако база данных может не находиться в папке _ данных приложения . Сведения о том, где будет создана база данных, см. в разделе Code First к новой базе данных.

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

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

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

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

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

    Selecting_Package_Manager_Console

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

    enable-migrations -contexttypename SchoolContext
    

    Команда "включить-миграция"

    Эта команда создает папку 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 метод предназначен для вставки тестовых данных в базу данных после того, как Code First создаст или обновит ее.

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

Метод SEED запускается, когда Code First migrations создает базу данных и каждый раз, когда она обновляет базу данных до последней миграции. Цель метода начального значения заключается в том, чтобы можно было вставлять данные в таблицы, прежде чем приложение будет получать доступ к базе данных в первый раз.

В более ранних версиях Code First до выпуска миграций были распространены Seed методы для вставки тестовых данных, так как при каждом изменении модели во время разработки база данных была полностью удалена и создана заново с нуля. При использовании Code First Migrations тестовые данные сохранены после изменения базы данных, поэтому, как правило, не требуется включать данные тестирования в метод 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 методе см. в разделе использование метода AddOrUpdate EF 4,3 в блоге Юлия Лерман.

    Код, добавляющий 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 метода и обработке избыточных данных, таких как два учащихся с именем "Александр Carson", см. в разделе Заполнение и отладка Entity Framework (EF) баз данных в блоге Рик Андерсон (.

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

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

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

    add-migration InitialCreate
    update-database
    

    add-migrationКоманда добавляет в папку миграций файл [датестамп] _ 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 -файл — в папке _ данных приложения проекта, так как это значение, указанное в строке подключения.

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

  1. В меню вид выберите пункт Обозреватель сервера.

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

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

  4. В диалоговом окне Добавление соединения введите (LocalDB) \V11.0 в поле имя сервера. В поле выберите или введите имя базы данных выберите ContosoUniversity.

  5. Нажмите кнопку ОК.

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

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

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

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

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

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

    • Имя контроллера: студентконтроллер.

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

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

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

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

      Add_Controller_dialog_box_for_Student_controller

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

    private SchoolContext db = new SchoolContext();
    

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

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

    В представлении студент\индекс.кштмл этот список отображается в таблице:

    <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, чтобы запустить проект.

    Щелкните вкладку students (учащиеся ), чтобы просмотреть тестовые данные, Seed вставленные методом.

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

Соглашения

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

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

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

Сводка

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

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