Для разработки новых приложений мы рекомендуем ASP.NET Core Razor Pages по ASP.NET MVC контроллеры и представления. For new development, we recommend ASP.NET Core Razor Pages over ASP.NET MVC controllers and views. Для следующего вида серии руководств см. в разделе с помощью Razor Pages, руководства: Начало работы с Razor Pages в ASP.NET Core. For a tutorial series similar to this one using Razor Pages, see Tutorial: Get started with Razor Pages in ASP.NET Core. Новый учебник. The new tutorial:
- проще для выполнения; Is easier to follow.
- содержит больше рекомендаций по EF Core; Provides more EF Core best practices.
- использует более эффективные запросы; Uses more efficient queries.
- более актуально, так как используются новейшие API; Is more current with the latest API.
- охватывает дополнительные возможности; Covers more features.
- является предпочтительным подходом для разработки новых приложений. Is the preferred approach for new application development.
В этой серии руководств вы узнаете, как создать приложение ASP.NET MVC 5, использующий Entity Framework 6 для доступа к данным. In this series of tutorials, you learn how to build an ASP.NET MVC 5 application that uses Entity Framework 6 for data access. В этом учебнике используется Code First рабочего процесса. This tutorial uses the Code First workflow. Сведения о том, как выбрать Code First, Database First или Model First, см. в разделе создать модель. For information about how to choose between Code First, Database First, and Model First, see Create a model.
В этой серии руководств описывается построение примера приложения университета Contoso. This tutorial series explains how to build the Contoso University sample application. Пример приложения веб-сайт простой университета. The sample application is a simple university website. С ним вы можете просматривать и обновлять учащихся, курсах и сведения о преподавателе. With it, you can view and update student, course, and instructor information. Ниже приведены два созданных экранов. Here are two of the screens you create:


В этом учебнике рассмотрены следующие задачи. In this tutorial, you:
- Создать веб-приложение MVC Create an MVC web app
- Настройка стиля сайта Set up the site style
- Установка Entity Framework 6 Install Entity Framework 6
- Создание модели данных Create the data model
- Создание контекста базы данных Create the database context
- Инициализация базы данных с тестовыми данными Initialize DB with test data
- Настройка EF 6 для использования LocalDB Set up EF 6 to use LocalDB
- Создание контроллера и представлений Create controller and views
- Просмотр базы данных View the database
Предварительные требования Prerequisites
Создать веб-приложение MVC Create an MVC web app
Откройте Visual Studio и создайте C# веб-проекта с помощью веб-приложение ASP.NET (.NET Framework) шаблона. Open Visual Studio and create a C# web project using the ASP.NET Web Application (.NET Framework) template. Назовите проект ContosoUniversity и выберите ОК. Name the project ContosoUniversity and select OK.

В новый веб-приложение ASP.NET — ContosoUniversityвыберите MVC. In New ASP.NET Web Application — ContosoUniversity, select MVC.

По умолчанию проверки подлинности параметру присваивается без проверки подлинности. By default, the Authentication option is set to No Authentication. В этом учебнике веб-приложение не требует пользователи выполняли вход. For this tutorial, the web app doesn’t require users to sign in. Кроме того он не ограничивает доступ, в зависимости от того, кто выполнил вход. Also, it doesn’t restrict access based on who’s signed in.
Нажмите кнопку ОК, чтобы создать проект. Select OK to create the project.
Настройка стиля сайта Set up the site style
Выполните незначительную настройку меню, макета и домашней страницы сайта. A few simple changes will set up the site menu, layout, and home page.
Откройте ViewsShared\_Layout.cshtmlи внесите следующие изменения: Open ViewsShared\_Layout.cshtml, and make the following changes:
- Замените все вхождения «My ASP.NET Application» и «Имя приложения» на «Contoso University». Change each occurrence of "My ASP.NET Application" and "Application name" to "Contoso University".
- Добавление пунктов меню для учащихся, курсов, преподавателей и отделов и удалите запись контакта. Add menu entries for Students, Courses, Instructors, and Departments, and delete the Contact entry.
Изменения выделены в следующем фрагменте кода: The changes are highlighted in the following code snippet:
В ViewsHomeIndex.cshtml, замените содержимое файла следующим кодом, который заменяет текст о ASP.NET и MVC об этом приложении: In ViewsHomeIndex.cshtml, replace the contents of the file with the following code to replace the text about ASP.NET and MVC with text about this application:
Нажмите клавиши Ctrl + F5 для запуска веб-сайта. Press Ctrl+F5 to run the web site. Появится домашняя страница с меню. You see the home page with the main menu.
Установка Entity Framework 6 Install Entity Framework 6
Из средства меню, выберите диспетчер пакетов NuGet, а затем выберите консоль диспетчера пакетов. From the Tools menu, choose NuGet Package Manager, and then choose Package Manager Console.
В консоль диспетчера пакетов окно, введите следующую команду: In the Package Manager Console window, enter the following command:
Этот шаг является одним из нескольких шагов с учебником можно сделать вручную, но, могло быть сделано автоматически с помощью функции формирования шаблонов ASP.NET MVC. This step is one of a few steps that this tutorial has you do manually, but that could have been done automatically by the ASP.NET MVC scaffolding feature. Вы выполняете их вручную, чтобы вы могли видеть шаги, необходимые для использования Entity Framework (EF). You’re doing them manually so that you can see the steps required to use Entity Framework (EF). Вы воспользуетесь формирования шаблонов позже для создания контроллера и представлений MVC. You’ll use scaffolding later to create the MVC controller and views. Альтернативным вариантом является для формирования шаблонов автоматически установить пакет EF NuGet создать класс контекста базы данных и создания строки подключения. An alternative is to let scaffolding automatically install the EF NuGet package, create the database context class, and create the connection string. Когда вы будете готовы сделать это таким образом, что необходимо сделать всего лишь пропустить эти шаги и сформировать шаблон контроллера MVC после создания классов сущностей. When you’re ready to do it that way, all you have to do is skip those steps and scaffold your MVC controller after you create your entity classes.
Создание модели данных Create the data model
Теперь необходимо создать классы сущностей для приложения университета Contoso. Next you’ll create entity classes for the Contoso University application. Сначала вы возьмете следующих трех сущностей: You’ll start with the following three entities:
Курс регистрации учащегося Course Enrollment Student
| Сущности Entities | Relationship Relationship |
|---|---|
| Курс для регистрации Course to Enrollment | один ко многим One-to-many |
| Учащегося для регистрации Student to Enrollment | один ко многим One-to-many |
Между сущностями Student и Enrollment , а также между сущностями Course и Enrollment существует отношение "один ко многим". There’s a one-to-many relationship between Student and Enrollment entities, and there’s a one-to-many relationship between Course and Enrollment entities. Другими словами, учащийся может быть зарегистрирован в любом количестве курсов, а в отдельном курсе может быть зарегистрировано любое количество учащихся. In other words, a student can be enrolled in any number of courses, and a course can have any number of students enrolled in it.
В следующих разделах вы создадите класс для каждого из этих сущностей. In the following sections, you’ll create a class for each one of these entities.
При попытке компиляции проекта до завершения создания всех этих классов сущностей, вы получите ошибки компилятора. If you try to compile the project before you finish creating all of these entity classes, you’ll get compiler errors.
Сущность Student The Student entity
В моделей папке создайте файл класса с именем Student.cs щелкнув правой кнопкой папку, в обозревателе решений и выбрав добавить > Класс. In the Models folder, create a class file named Student.cs by right-clicking on the folder in Solution Explorer and choosing Add > Class. Замените код шаблона следующим кодом: Replace the template code with the following code:
Свойство ID будет использоваться в качестве столбца первичного ключа в таблице базы данных, соответствующей этому классу. The ID property will become the primary key column of the database table that corresponds to this class. По умолчанию Entity Framework интерпретирует свойство с именем ID или classname ID как первичный ключ. By default, Entity Framework interprets a property that’s named ID or classname ID as the primary key.
Свойство Enrollments является свойством навигации. The Enrollments property is a navigation property. Свойства навигации содержат другие сущности, связанные с этой сущностью. Navigation properties hold other entities that are related to this entity. В этом случае Enrollments свойство Student сущность будет содержать все Enrollment сущностей, которые связаны Student сущности. In this case, the Enrollments property of a Student entity will hold all of the Enrollment entities that are related to that Student entity. Другими словами если заданный Student строк в базе данных имеет два связанных Enrollment строк (значение строки, которые содержат первичный ключ этого учащегося в их StudentID внешний ключевой столбец), в котором Student сущности Enrollments свойство навигации будет содержать две этих Enrollment сущностей. In other words, if a given Student row in the database has two related Enrollment rows (rows that contain that student’s primary key value in their StudentID foreign key column), that Student entity’s Enrollments navigation property will contain those two Enrollment entities.
Свойства навигации, обычно определяются как virtual таким образом, чтобы они можно воспользоваться преимуществами определенные функциональные возможности Entity Framework, такие как отложенная загрузка. Navigation properties are typically defined as virtual so that they can take advantage of certain Entity Framework functionality such as lazy loading. (Отложенная загрузка, будет рассматриваться далее в чтение связанных данных далее в этой серии руководств.) (Lazy loading will be explained later, in the Reading Related Data tutorial later in this series.)
Если свойство навигации может содержать несколько сущностей (как в отношениях "многие ко многим" или "один ко многим"), оно должно иметь тип списка, допускающий добавление, удаление и обновление записей, такой как ICollection . If a navigation property can hold multiple entities (as in many-to-many or one-to-many relationships), its type must be a list in which entries can be added, deleted, and updated, such as ICollection .
Сущность Enrollment The Enrollment entity
В папке Models создайте файл Enrollment.cs и замените существующий код следующим кодом: In the Models folder, create Enrollment.cs and replace the existing code with the following code:
EnrollmentID Свойство будет иметь первичный ключ; эта сущность использует classname ID шаблонов вместо ID , как вы видели в Student сущности. The EnrollmentID property will be the primary key; this entity uses the classname ID pattern instead of ID by itself as you saw in the Student entity. Как правило, следует выбирать один шаблон, который будет использоваться в рамках всей модели данных. Ordinarily you would choose one pattern and use it throughout your data model. В этом случае демонстрируется возможность использования любого из шаблонов. Here, the variation illustrates that you can use either pattern. В этом руководстве, вы увидите как с помощью ID без classname позволяет упростить реализацию наследования в модели данных. In a later tutorial, you’ll see how using ID without classname makes it easier to implement inheritance in the data model.
Grade Свойство перечисления. The Grade property is an enum. Знак вопроса после Grade объявление типа указывает, что Grade свойство допускает значения NULL. The question mark after the Grade type declaration indicates that the Grade property is nullable. Корпоративного класса, который имеет значение null отличается от нулевой оценки тем — значение null означает, что это оценка не известна или еще не назначена. A grade that’s null is different from a zero grade — null means a grade isn’t known or hasn’t been assigned yet.
Свойство StudentID представляет собой внешний ключ. Ему соответствует свойство навигации Student . The StudentID property is a foreign key, and the corresponding navigation property is Student . Сущность Enrollment связана с одной сущностью Student , поэтому это свойство может содержать одну сущность Student (в отличие от представленного ранее свойства навигации Student.Enrollments , которое может содержать несколько сущностей Enrollment ). An Enrollment entity is associated with one Student entity, so the property can only hold a single Student entity (unlike the Student.Enrollments navigation property you saw earlier, which can hold multiple Enrollment entities).
Свойство CourseID представляет собой внешний ключ. Ему соответствует свойство навигации Course . The CourseID property is a foreign key, and the corresponding navigation property is Course . Сущность Enrollment связана с одной сущностью Course . An Enrollment entity is associated with one Course entity.
Платформа Entity Framework интерпретирует свойство как свойство внешнего ключа, если оно имеет имя (например, StudentID для Student свойство навигации с момента Student — первичный ключ сущности ID ). Entity Framework interprets a property as a foreign key property if it’s named
I have a problem with a Visual Studio solution using Entity Framework 6 + Code First + Oracle 12c. I’m not sure it is properly configured, or if I missed something simple.
I tried to look for a sample project as a start, but was not able to find — google search, stackoverflow etc.
Is there a minimalistic sample project somewhere, which tries to create the database when runs?
Update: Just to make sure, I’m not asking anyone to create a sample for me. Before I’ll do it, I want to make sure there is really no existing sample (which is strange for me, but very well might be the case).
В своей статье «Entity Framework 6: The Ninja Edition» в прошлом номере (msdn.microsoft.com/magazine/dn532202) я описала многие из новых средств в Entity Framework 6 (EF6). Однако у меня не было возможности подробно рассказать о каждом из них, поэтому сегодня я углублюсь в некоторые усовершенствования в EF6, специфичные для Code First. Два из них относятся к сопоставлениям Code First, а остальные — к миграциям Code First.
Одновременная загрузка множества сопоставлений Fluent API
Есть два способа указать для модели сопоставления Fluent API (ваших классов с базой данных). Один из них — напрямую в методе OnModelCreating класса DbContext, например:
Когда у вас много сопоставлений, вы можете организовать их по типу в индивидуальные классы EntityTypeConfiguration, которые потом добавите в средство формирования модели (model builder), используя примерно такой код:
Однако при наличии множества сопоставлений для множества сущностей дело может закончиться тем, что в OnModelCreating придется включать уйму повторяющихся методов modelBuilder.Configurations.Add. Чтобы исключить эту монотонную работу, теперь можно загружать все EntityTypeConfiguration из конкретной сборки с помощью одного метода. Ниже я использую новый метод AddFromAssembly для загрузки конфигураций, указанных в исполняемой сборке для приложения:
Приятная особенность этого метода в том, что он не ограничен областью видимости конфигураций, которые он будет загружать. Ваши классы EntityTypeConfiguration можно даже помечать как закрытые, и этот метод все равно найдет их. Более того, AddFromAssembly также понимает иерархии наследования в EntityTypeConfigurations.
AddFromAssembly — это один из многочисленных результатов работы Унаи Зорилла (Unai Zorrilla). Подробности см. в публикации в его блоге «EF6: Setting Configurations Automatically» (bit.ly/16OBuJ5) — и не пожалейте времени черкнуть ему пару слов благодарности в комментариях к этой публикации.
Определение собственной схемы по умолчанию
В своей статье «Playing with the EF6 Alpha» в номере за март 2013 г. (msdn.microsoft.com/magazine/jj991973) я немного рассказала о поддержке схем для Code First. Одно из новшеств — сопоставление, которое можно конфигурировать в OnModelCreating: HasDefaultSchema. Это позволяет вам указывать схему базы данных для всех таблиц, с которыми сопоставляется контекст, вместо использования dbo, предлагаемого EF по умолчанию. В статье «Entity Framework 6: The Ninja Edition» я показывала некоторый исходный SQL-код при обсуждении DbTransactions:
Вероятно, вы заметили схему Casino, указанную мной в SQL. Причина, по которой у меня была схема Casino в том, что я задала ее в методе OnModelCreating своего DbContext (CasinoSlotsModel):
Я также рассказывала о новой поддержке миграций (migrations) для Code First в EF6, выполняемых применительно к базе данных, в которой есть другие схемы. Так как здесь ничего не изменилось со времен альфа-версии EF6, предлагаю почитать о них в предыдущих статьях из этой рубрики.
Скрипты миграций для перестройки базы данных с любой точки
Одно из новшеств для миграций Code First, перечисленных в спецификациях (и в любой статье, где просто повторяют спецификации), — «идемпотентные скрипты миграций». Возможно у вас есть ученая степень в области компьютерных наук или вы являетесь DBA (администратором баз данных). Но ко мне это не относится, так что мне пришлось искать значение слова «идемпотентный». Согласно википедии, где есть ссылка на одного инженера из IBM (bit.ly/9MIrRK): «В компьютерных науках термин «идемпотентный» используется… для описания операции, которая будет давать одни и те же результаты как при разовом выполнении, так и при многократном».
В мире баз данных термин «идемпотентный» может быть использован для описания SQL-скрипта, который всегда одинаково влияет на базу данных независимо от ее состояния. В случае Code First перед выполнением миграции такой скрипт будет проверять, а не выполняется ли уже такая миграция. Эта функциональность связана с параметром –script команды Update-Database.
EF всегда позволяла создавать скрипты, выполняемые на всех этапах миграции от конкретной начальной точки (источника) и (не обязательно) до явно указанной конечной точки (цели). Следующая NuGet-команда активирует это поведение:
Новшество заключается в том, что генерируемые скрипты теперь намного «интеллектуальнее», когда вы вызываете команду особым образом:
Это также работает, если вы заменяете $InitialDatabase на 0, хотя нет никаких гарантий, что эта альтернатива будет поддерживаться в следующих версиях.
В ответ скрипт начинает с начальной миграции и выполняется до самой последней миграции. Вот почему в синтаксисе не предоставляются явным образом имена миграций цели (target) или источника (source).
Но в случае этой команды EF6 добавляет в скрипт логику, которая перед выполнением SQL-кода для конкретной миграции проверяет, какие миграции уже применяются. Вот пример кода, который можно увидеть в скрипте:
Этот код проверяет таблицу __MigrationHistory, чтобы выяснить, выполнялся ли уже скрипт AddedSomeNewPropertyToCasino в базе данных. Если да, то SQL-код из этой миграции выполняться не будет. До EF6 такой скрипт просто запускал SQL-код, не проверяя, выполнялся ли он ранее.
Таблицы истории миграций, дружественные к провайдеру
EF6 позволяет настраивать, как определяется таблица __MigrationHistory, используя функциональность Customizable Migrations History Table. Это важно, если вы применяете сторонние провайдеры данных, которые предъявляют требования, отличные от действующих по умолчанию. На рис. 1 показана схема таблицы по умолчанию.
Рис. 1. Схема по умолчанию для таблицы __MigrationHistory
Вот пример того, насколько это может быть полезно. На сайте CodePlex один из разработчиков заметил: поскольку каждый символ (char) в двух PK может быть больше одного байта, он получал ошибку из-за того, что длина составного ключа (compound key), созданного из MigrationId и ContextKey, превышала допустимую длину ключа для таблицы MySQL: 767 байтов (bit.ly/18rw1BX). Чтобы решить эту проблему, группа MySQL использует HistoryContext на внутреннем уровне, чтобы изменять длину полей двух ключей, и параллельно работает над EF6-версией MySQL Connector for ADO.NET (bit.ly/7uYw2a).
Обратите внимание на рис. 1, что таблица __MigrationHistory получает ту же схему, которую я определила для контекста, используя HasSchema: Casino. У вас могут действовать соглашения о том, что таблицы, не содержащие данных (non-data tables), должны использовать схему с ограниченными разрешениями, поэтому вам может понадобиться изменить имя схемы этой таблицы. Сделать это можно с помощью HistoryContext, например, указав, что следует использовать схему admin.
HistoryContext наследует от DbContext, поэтому код должен быть вам более-менее знаком, если вы работали в прошлом с DbContext и Code First. На рис. 2 показан класс HistoryContext, определенный мной для того, чтобы указать схему admin.
Рис. 2. Собственный HistoryContext для переопределения таблицы __MigrationHistory
Вы также можете использовать знакомые API-вызовы вроде Property().HasColumnType, HasMaxLength или HasColumnName. Например, если вам нужно изменить длину ContextKey, можно сделать так:
Если вы читали мою статью в прошлом номере, то должны иметь представление о DbConfiguration в EF6. С его помощью вы даете знать собственной модели о файле CustomHistoryContext. В конструкторе своего DbConfiguration вам нужно указать используемый HistoryContext. Здесь я задаю контекст для провайдера SQL Server, чтобы использовать CustomHistoryContext:
Функциональность, отвечающая за инициализацию базы данных и миграции, увидит этот дополнительный контекст и соответственно сконструирует SQL. Таблица на рис. 3 была создана с применением собственного HistoryContext, чтобы сменить имя схемы таблицы __MigrationHistory на admin. (Я не включила пример кода, иллюстрирующий изменение длины поля.)
Рис. 3. Настроенная таблица __MigrationHistory
HistoryContext — мощная функциональность, но ею следует пользоваться с осторожностью. Хорошо, если применяемый вами провайдер базы данных уже задействует ее, чтобы указывать таблицу __MigrationHistory, релевантную для целевой базы данных, и вам не придется задумываться об этом. В ином случае советую прочитать документацию MSDN по этой функциональности и учесть приведенные в ней рекомендации (bit.ly/16eK2pD).
Создание собственных операций миграции
Если вы ранее пользовались миграциями — не автоматически, а явным образом создавая и выполняя миграции из окна Package Manager Console, то, вероятно, изучали файлы миграции, создаваемые командой add-migration. В таком случае вы могли обнаружить, что миграции Code First имеют строго типизированный API для описания каждого изменения, которое нужно внести в схему базы данных: System.Data.Entity.Migrations.DbMigration.
На рис. 4 показан пример метода CreateTable, который задает количество атрибутов.
Рис. 4. Метод DbMigrations.CreateTable
Затем провайдеры транслируют эти API-вызовы в SQL-код, специфичный для базы данных.
Существуют методы для создания таблиц и индексов, создания или изменения свойств, удаления объектов и др. Это довольно богатый API, как можно представить из возможностей, перечисленных на рис. 5; здесь же есть возможность прямого выполнения какого-либо SQL-кода. Но в некоторых случаях его может не хватить для каких-то ваших потребностей. Например, нет никаких методов для создания представлений базы данных, указания разрешений или множества других операций.
Рис. 5. Операции над схемой базы данных DbMigrations
И здесь сообщество вновь приходит на помощь. В EF6 теперь можно создавать собственные операции миграций, которые можно вызывать, соответственно настраивая классы миграции, генерируемые командой add-migration. За это мы должны поблагодарить другого разработчика из сообщества CodePlex — Инаки Элькоро (Inaki Elcoro), также известного под ником iceclow.
Чтобы создать свою операцию, надо выполнить несколько этапов. Я расскажу о сути каждого из этих этапов. Полный код и то, как организуются эти этапы, см. в исходном коде, который можно скачать для этой статьи.
- Определяем операцию. Здесь я определила CreateViewOperation (рис. 6).
- Создаем метод расширения, чтобы указать на операцию. Это упрощает ее вызов из DbMigration:
- Определяем SQL для операции в методе Generate своего класса SqlServerMigrationSqlGenerator, как показано на рис. 7.
- Сообщаем классу DbConfiguration использовать наш класс SqlServerMigrationSqlGenerator:
Рис. 6. Собственная операция миграции для создания представления базы данных
Рис. 7. Собственный класс SqlServerMigrationSqlGenerator
Теперь можно использовать новую операцию в файле миграции, и Update-Database будет знать, что с ней делать. На рис. 8 показана операция CreateView в действии; заодно я напоминаю вам о необходимости создать парную операцию для удаления представления, которая будет вызываться методом Down, если вам потребуется раскрутить эту миграцию.
Рис. 8. Применение новой операции CreateView
После вызова Update-Database вы увидите новое представление моей базы данных (рис. 9).
Рис. 9. Только что созданное представление, сгенерированное Update-Database
Code First продолжает развиваться
Создав базовые средства Code First, Microsoft и разработчики из сообщества воспользовались возможностью начать шлифовку Code First в EF6 и ввели ряд средств, которые теперь выигрывают от большей гибкости. Но эта работа не прекратится с выпуском EF6. Если вы включите фильтр рабочих элементов на CodePlex для версий выше 6.0.1 (bit.ly/1dA0LZf), то увидите, что в будущих версиях EF6 и Code First появится еще больше возможностей и усовершенствований. Эти элементы находятся на разных стадиях. Возможно, вы найдете что-то, над чем вам будет интересно поработать.
Джули Лерман (Julie Lerman) — Microsoft MVP, преподаватель и консультант по .NET, живет в Вермонте. Часто выступает на конференциях по всему миру и в группах пользователей по тематике, связанной с доступом к данным и другими технологиями Microsoft .NET. Ведет блог thedatafarm.com/blog и является автором серии книг «Programming Entity Framework» (O’Reilly Media, 2010), в том числе «Code First Edition» (2011) и «DbContext Edition» (2012), также выпущенных издательством O’Reilly Media. Вы можете читать ее заметки в twitter.com/julielerman и смотреть ее видеокурсы для Pluralsight на juliel.me/PS-Videos.
Выражаю благодарность за рецензирование статьи эксперту Microsoft Роуэну Миллеру (Rowan Miller).






