События
Присоединение к вызову ИИ Навыков
8 апр., 15 - 28 мая, 07
Отточите свои навыки ИИ и введите подметки, чтобы выиграть бесплатный экзамен сертификации
Зарегистрируйтесь!Этот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Авторы: Том Дайкстра (Tom Dykstra) и Рик Андерсон (Rick Anderson)
Это руководство описывает MVC-модель ASP.NET Core и Entity Framework Core с контроллерами и представлениями. Razor Pages — это альтернативная модель программирования. Для новой разработки мы рекомендуем использовать Razor Pages, а не MVC с контроллерами и представлениями. См. версию этого руководства для Razor Pages. В каждом руководстве содержатся уникальные материалы:
В руководстве по MVC содержатся материалы, которых нет в руководстве по Razor Pages:
В руководстве по Razor Pages содержатся материалы, которых нет в этом руководстве:
На примере веб-приложения для университета Contoso демонстрируется процесс создания веб-приложений ASP.NET Core MVC с помощью Entity Framework (EF) Core и Visual Studio.
В этом примере приложения реализуется веб-сайт вымышленного университета Contoso. На нем предусмотрены различные функции, в том числе прием учащихся, создание курсов и назначение преподавателей. Это первый учебник из серии, в котором описывается создание примера приложения для университета Contoso.
Это руководство не было обновлено для ASP.NET Core 6 или более поздней версии. Инструкции руководства не будут работать правильно, если вы создаете проект, предназначенный для ASP.NET Core 6 или более поздней версии. Например, веб-шаблоны ASP.NET Core 6 и более поздних версий используют минимальную модель размещения, которая объединяет и Startup.cs
объединяет Program.cs
один Program.cs
файл.
Еще одно различие, введенное в .NET 6, — это функция NRT (ссылочные типы, допускающие значение NULL). Шаблоны проектов позволяют включить эту функцию по умолчанию. Проблемы могут возникать, когда EF рассматривает свойство, необходимое в .NET 6, которое допускает значение NULL в .NET 5. Например, страница create Student не будет автоматически завершатся ошибкой, если Enrollments
свойство не имеет значения NULL или asp-validation-summary
вспомогательный тег изменяется с ModelOnly
All
.
Мы рекомендуем установить и использовать пакет SDK для .NET 5 для этого руководства. Пока это руководство не будет обновлено, см. статью Razor Pages with Entity Framework Core в ASP.NET Core . Руководство 1 из 8 по использованию Entity Framework с ASP.NET Core 6 или более поздней версии.
В инструкциях для Visual Studio используется SQL Server LocalDB, версия SQL Server Express, которая работает только в Windows.
Если вы столкнулись с проблемами, для их решения можно попробовать сравнить свой код с кодом готового проекта. Список распространенных ошибок и способы их устранения см. в разделе "Устранение неполадок" последнего руководства серии. Если вы не найдете, что вам нужно, вы можете отправить вопрос, чтобы StackOverflow.com для ASP.NET Core или EF Core.
Совет
Эта серия включает в себя 10 учебников, содержание каждого из которых базируется на предыдущих учебниках. После успешного завершения каждого руководства рекомендуется сохранять копию проекта. Таким образом, при возникновении проблем вы сможете вернуться к предыдущему учебнику, а не к началу серии.
Приложение, создаваемое в этих руководствах, является простым веб-сайтом университета.
Пользователи приложения могут просматривать и обновлять сведения об учащихся, курсах и преподавателях. Вот несколько экранов в приложении:
ContosoUniversity
в поле Имя проекта. Очень важно использовать именно такое имя с учетом регистра символов, чтобы пространства имен (namespace
) совпадали при копировании кода.Несколько основных изменений настраивают макет, меню сайта и главную страницу.
Откройте Views/Shared/_Layout.cshtml
и внесите следующие изменения.
ContosoUniversity
на Contoso University
. Таких элементов будет три.Предыдущие изменения выделены в следующем коде:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2020 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Замените содержимое файла Views/Home/Index.cshtml
следующей разметкой:
@{
ViewData["Title"] = "Home Page";
}
<div class="jumbotron">
<h1>Contoso University</h1>
</div>
<div class="row">
<div class="col-md-4">
<h2>Welcome to Contoso University</h2>
<p>
Contoso University is a sample application that
demonstrates how to use Entity Framework Core in an
ASP.NET Core MVC web application.
</p>
</div>
<div class="col-md-4">
<h2>Build it from scratch</h2>
<p>You can build the application by following the steps in a series of tutorials.</p>
<p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial »</a></p>
</div>
<div class="col-md-4">
<h2>Download it</h2>
<p>You can download the completed project from GitHub.</p>
<p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/5cu-final">See project source code »</a></p>
</div>
</div>
Нажмите клавиши CTRL+F5, чтобы запустить проект, и выберите в меню Отладка > Запуск без отладки. Домашняя страница отображается с вкладками для страниц, созданных в этом руководстве.
В этом учебнике используется SQL Server, для которого требуется пакет поставщика Microsoft.EntityFrameworkCore.SqlServer.
Этот пакет EF SQL Server и его зависимости, Microsoft.EntityFrameworkCore
и Microsoft.EntityFrameworkCore.Relational
, обеспечивают поддержку среды выполнения для платформы EF.
Добавьте пакет NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore. Введите в консоли диспетчера пакетов (PMC) следующие команды, чтобы добавить пакеты NuGet:
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Пакет Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
NuGet предоставляет ASP.NET ПО промежуточного слоя Core для EF Core страниц ошибок. Это ПО промежуточного слоя помогает обнаруживать и диагностировать ошибки при EF Core миграции.
Сведения о других поставщиках баз данных, доступных для EF Coreпоставщиков баз данных, см. в разделе "Поставщики баз данных".
Для этого приложения будут созданы следующие классы сущностей:
У приведенных выше сущностей есть следующие отношения.
Student
и Enrollment
действует связь "один ко многим". Учащегося можно зачислить на любое число курсов.Course
и Enrollment
действует связь "один ко многим". На курс может быть зачислено любое количество учащихся.В следующих разделах создается класс для каждой из этих сущностей.
В папке Models создайте класс Student
, содержащий следующий код:
using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
}
Свойство ID
используется в качестве столбца первичного ключа (ПК) в таблице базы данных, соответствующей этому классу. По умолчанию платформа EF интерпретирует в качестве первичного ключа свойство ID
или classnameID
. Например, ПК может называться StudentID
, а не ID
.
Свойство Enrollments
является свойством навигации. Свойства навигации содержат другие сущности, связанные с этой сущностью. Свойство Enrollments
сущности Student
:
Enrollment
, связанные с этой сущностью Student
.Student
базе данных есть две связанные Enrollment
строки: Student
сущности Enrollments
содержит эти две сущности Enrollment
.Строки Enrollment
содержат значение первичного ключа учащегося в столбце внешнего ключа (StudentID
) .
Если свойство навигации содержит несколько сущностей:
ICollection<T>
, List<T>
или HashSet<T>
.Связи "многие ко многим" и "один ко многим" могут содержать несколько сущностей. Если используется ICollection<T>
, платформа EF по умолчанию создает коллекцию HashSet<T>
.
В папке Models создайте класс Enrollment
, содержащий следующий код:
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 Course Course { get; set; }
public Student Student { get; set; }
}
}
Свойство EnrollmentID
— это ПК. Эта сущность использует шаблон classnameID
вместо самого по себе ID
. Сущность Student
использовала шаблон ID
. Некоторые разработчики предпочитают использовать один шаблон во всей модели данных. В этом учебнике демонстрируется возможность использования любого из шаблонов. В одном из следующих учебников показано, за счет чего использование ID
без имени класса позволяет упростить реализацию наследования в модели данных.
Свойство Grade
имеет тип enum
. Знак ?
после объявления типа Grade
указывает, что свойство Grade
допускает значение NULL. Оценка со значением null
отличается от нулевой оценки. При значении null
оценка еще не известна или не назначена.
Свойство StudentID
представляет собой внешний ключ (ВК). Ему соответствует свойство навигации Student
. Сущность Enrollment
связана с одной сущностью Student
, поэтому свойство содержит только отдельную сущность Student
. Она отличается от свойства навигации Student.Enrollments
, которое содержит несколько сущностей Enrollment
.
Свойство CourseID
представляет собой ВК. Ему соответствует свойство навигации Course
. Сущность Enrollment
связана с одной сущностью Course
.
Entity Framework интерпретирует свойство как свойство ВК, если оно называется <
имя_свойства_навигации><
имя_свойства_первичного_ключа>
. Например, StudentID
для свойства навигации Student
, так как сущность Student
имеет значение ПК ID
. Свойства ВК также могут называться <
имя_свойства_первичного_ключа>
. Например, CourseID
, так как сущность Course
имеет значение ПК CourseID
.
В папке Models создайте класс Course
, содержащий следующий код:
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 ICollection<Enrollment> Enrollments { get; set; }
}
}
Свойство Enrollments
является свойством навигации. Сущность Course
может быть связана с любым числом сущностей Enrollment
.
Атрибут DatabaseGenerated описан в следующем учебнике. Этот атрибут позволяет ввести ПК для курса, а не использовать базу данных, чтобы создать его.
Контекст базы данных DbContext — это основной класс, который координирует функциональные возможности EF для определенной модели данных. Этот класс является производным от класса Microsoft.EntityFrameworkCore.DbContext
. Производный класс DbContext
указывает сущности, которые включаются в модель данных. Некоторые расширения функциональности EF можно настроить. В этом проекте соответствующий класс называется SchoolContext
.
В папке проекта создайте папку с именем Data
.
В папке Data создайте файл SchoolContext
, содержащий следующий код:
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
}
}
Представленный выше код создает свойство DbSet
для каждого набора сущностей. Терминология EF:
Инструкции DbSet<Enrollment>
и DbSet<Course>
можно опустить. Это не нарушит функциональность. EF включает их неявно, так как
Student
ссылается на сущность Enrollment
,Enrollment
ссылается на сущность Course
,При создании базы данных платформа EF создает таблицы с именами, соответствующими именам свойств в DbSet
. Имена свойств для коллекций обычно указаны во множественном числе. Например, используйте идентификатор Students
вместо Student
. В среде разработчиков нет единого мнения о том, следует ли использовать имена таблиц во множественном числе. В этих учебниках вместо принятого по умолчанию способа таблицам в DbContext
присваиваются имена в единственном числе. Чтобы сделать это, добавьте выделенный ниже код после последнего свойства DbSet.
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
ASP.NET Core поддерживает внедрение зависимостей. С помощью внедрения зависимостей службы, например контекст базы данных EF, регистрируются во время запуска приложения. Затем компоненты, которые используют эти службы, например контроллеры MVC, обращаются к ним через параметры конструктора. Код конструктора контроллера, который получает экземпляр контекста, будет приведен позднее в этом учебнике.
Чтобы зарегистрировать SchoolContext
как службу, откройте файл Startup.cs
и добавьте выделенные строки в метод ConfigureServices
.
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ContosoUniversity
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllersWithViews();
}
Имя строки подключения передается в контекст путем вызова метода для объекта DbContextOptionsBuilder
. При локальной разработке система конфигурации ASP.NET Core считывает строку подключения из файла appsettings.json
.
Откройте файл appsettings.json
и добавьте строку подключения, как показано в следующей разметке:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Добавьте AddDatabaseDeveloperPageExceptionFilter в ConfigureServices
, как показано в следующем коде:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddControllersWithViews();
}
AddDatabaseDeveloperPageExceptionFilter
предоставляет полезные сведения об ошибках в среде разработки.
Строка подключения указывает базу данных SQL Server LocalDB. LocalDB — это упрощенная версия ядра СУБД SQL Server Express, предназначенная для разработки приложений и не ориентированная на использование в рабочей среде. LocalDB запускается по запросу в пользовательском режиме, поэтому настройки не слишком сложны. По умолчанию LocalDB создает файлы базы данных MDF в каталоге C:/Users/<user>
.
EF создает пустую базу данных. В этом разделе добавляется метод, который вызывается после создания базы данных и заполняет ее тестовыми данными.
Метод EnsureCreated
будет использоваться для автоматического создания базы данных. В одном из следующих учебников вы узнаете, как обрабатывать изменения модели с использованием Code First Migrations, что позволяет изменять схему базы данных вместо того, чтобы удалять и повторно создавать ее.
В папке Data создайте файл с именем DbInitializer
, содержащий следующий код:
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
context.Database.EnsureCreated();
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
};
foreach (Student s in students)
{
context.Students.Add(s);
}
context.SaveChanges();
var courses = new 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}
};
foreach (Course c in courses)
{
context.Courses.Add(c);
}
context.SaveChanges();
var enrollments = new Enrollment[]
{
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
};
foreach (Enrollment e in enrollments)
{
context.Enrollments.Add(e);
}
context.SaveChanges();
}
}
}
Предыдущий код проверяет, существует ли база данных:
List<T>
.Обновите Program.cs
, включив в него следующий код.
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Program.cs
выполняет следующие действия при запуске приложения:
DbInitializer.Initialize
.Initialize
, как показано в следующем коде:public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
host.Run();
}
При первом запуске приложения создается база данных, которая заполняется тестовыми данными. Каждый раз при изменении модели данных:
В последующих учебниках описывается, как изменить базу данных при изменении модели данных, не прибегая к ее удалению и повторному созданию. При изменении модели данных данные не теряются.
Используйте подсистему формирования шаблонов Visual Studio для добавления контроллера и представлений MVC, которые будут использовать платформу EF для запроса данных и их сохранения.
Автоматическое создание методов и представлений операций CRUD (создание, чтение, обновление и удаление) называется формированием шаблонов.
Controllers
и выберите Добавить > Создать шаблонный элемент.Подсистема формирования шаблонов Visual Studio создает файл StudentsController.cs
и набор представлений (файлы *.cshtml
), которые будут работать с контроллером.
Обратите внимание, что контроллер принимает SchoolContext
в качестве параметра конструктора.
namespace ContosoUniversity.Controllers
{
public class StudentsController : Controller
{
private readonly SchoolContext _context;
public StudentsController(SchoolContext context)
{
_context = context;
}
Технология внедрения зависимостей ASP.NET Core обеспечивает передачу экземпляра SchoolContext
в контроллер. Вы настраиваете ее в классе Startup
.
Контроллер содержит метод действия Index
, который отображает всех учащихся в базе данных. Этот метод получает список учащихся из набора сущностей Students, считывая свойство Students
экземпляра контекста базы данных:
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
Элементы асинхронного программирования в этом коде рассматриваются далее в этом учебнике.
В Views/Students/Index.cshtml
представлении отображается этот список в таблице:
@model IEnumerable<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<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>
</thead>
<tbody>
@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>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Нажмите клавиши CTRL+F5, чтобы запустить проект, и выберите в меню Отладка > Запуск без отладки.
Перейдите на вкладку Students (Учащиеся), чтобы просмотреть тестовые данные, добавленные методом DbInitializer.Initialize
. В зависимости от размеров окна браузера ссылку на вкладку Students
можно найти вверху страницы или щелкнув значок навигации в правом верхнем углу.
При запуске приложения метод DbInitializer.Initialize
вызывает EnsureCreated
. Платформа EF определила, что база данных отсутствует,
Initialize
заполняет базу данных данными.Для просмотра базы данных в Visual Studio используйте Обозреватель объектов SQL Server (SSOX).
ContosoUniversity1
для имени базы данных, которая находится в строке подключения в файле appsettings.json
.
Щелкните правой кнопкой мыши таблицу Student и выберите пункт Просмотреть данные, чтобы просмотреть данные в таблице.
Файлы базы данных *.mdf
и *.ldf
находятся в папке C:\Users\<имя_пользователя>.
Так как EnsureCreated
вызывается в методе инициализатора, который выполняется при запуске приложения, можно сделать следующее:
Student
.Например, при добавлении свойства EmailAddress
в класс Student
во вновь созданной таблице появится новый столбец EmailAddress
. В представлении не будет отображаться новое свойство EmailAddress
.
Объем кода, написанного для создания полной базы данных платформой EF, сведен к минимуму благодаря использованию соглашений EF.
DbSet
. Для сущностей, на которые не ссылается свойство DbSet
, в качестве имен таблиц используются имена классов сущностей.ID
или classnameID
распознаются как свойства ПК.<
имя_свойства_навигации><
имя_свойства_первичного_ключа>
. Например, StudentID
для свойства навигации Student
, так как сущность Student
имеет значение ПК ID
. Свойства ВК также могут называться <
имя_свойства_первичного_ключа>
. Например, EnrollmentID
, так как сущность Enrollment
имеет ПК EnrollmentID
.Стандартное поведение можно переопределить. Например, можно явно задать имена таблиц, как было показано ранее в этом учебнике. Имена столбцов и любое свойство можно задать в качестве ПК или ВК.
Асинхронное программирование — это режим по умолчанию для ASP.NET Core и EF Core.
Веб-сервер имеет ограниченное число потоков, поэтому при высокой загрузке могут использоваться все доступные потоки. В таких случаях сервер не может обрабатывать новые запросы до тех пор, пока не будут высвобождены потоки. В синхронном коде многие потоки могут быть заняты, не выполняя при этом какие-либо операции и ожидая завершения ввода-вывода. В асинхронном коде в то время, когда процесс ожидает завершения ввода-вывода, его поток высвобождается и может использоваться сервером для обработки других запросов. Таким образом, асинхронный код позволяет более эффективно использовать ресурсы сервера, который может обрабатывать больше трафика без задержек.
Во время выполнения асинхронный код использует немного больше служебных ресурсов, однако при низком объеме трафика этим можно пренебречь. Тем не менее в случае большого объема трафика это дает существенный выигрыш в производительности.
В следующем коде async
, Task<T>
, await
и ToListAsync
обеспечивают асинхронное выполнение кода.
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
async
указывает компилятору создавать обратные вызовы для частей тела метода и автоматически создавать возвращаемый объект Task<IActionResult>
.Task<IActionResult>
представляет текущую операцию с помощью результата типа IActionResult
.await
предписывает компилятору разделить метод на две части. Первая часть завершается операцией, которая запускается в асинхронном режиме. Вторая часть помещается в метод обратного вызова, который вызывается при завершении операции.ToListAsync
является асинхронной версией метода расширения ToList
.При написании асинхронного кода, который использует EF, нужно учитывать некоторые моменты:
ToListAsync
, SingleOrDefaultAsync
и SaveChangesAsync
. В их число не входят, например, инструкции, которые просто изменяют IQueryable
, такие как var students = context.Students.Where(s => s.LastName == "Davolio")
.await
.Дополнительные сведения об асинхронных методах программирования в .NET см. в разделе Обзор асинхронной модели.
Сведения об ограничении числа сущностей, возвращаемых в запросе, см. в статье Важные замечания о производительности.
Конфигурация ведения журналов обычно предоставляется разделом Logging
в файлах appsettings.{Environment}.json
. Чтобы регистрировать инструкции SQL, добавьте "Microsoft.EntityFrameworkCore.Database.Command": "Information"
в файл appsettings.Development.json
:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
}
},
"AllowedHosts": "*"
}
В приведенном выше коде JSON инструкции SQL отображаются в командной строке и в окне вывода Visual Studio.
Дополнительные сведения см. в статье Ведение журнала в ASP.NET Core и описании этой проблемы GitHub.
В следующем учебнике описано, как выполнять основные операции CRUD (создание, чтение, обновление и удаление).
Это руководство описывает MVC-модель ASP.NET Core и Entity Framework Core с контроллерами и представлениями. Razor Pages — это альтернативная модель программирования. Для новой разработки мы рекомендуем использовать Razor Pages, а не MVC с контроллерами и представлениями. См. версию этого руководства для Razor Pages. В каждом руководстве содержатся уникальные материалы:
В руководстве по MVC содержатся материалы, которых нет в руководстве по Razor Pages:
В руководстве по Razor Pages содержатся материалы, которых нет в этом руководстве:
Пример веб-приложения Contoso University демонстрирует создание веб-приложений ASP.NET Core 2.2 MVC с помощью Entity Framework (EF) Core 2.2 и Visual Studio 2019.
Это руководство не было обновлено для использования с версией ASP.NET Core 3.1. Оно обновлено для использования с ASP.NET Core 5.0.
В этом примере приложения реализуется веб-сайт вымышленного университета Contoso. На нем предусмотрены различные функции, в том числе прием учащихся, создание курсов и назначение преподавателей. Это первый учебник из серии, в котором с самого начала описывается построение примера приложения для университета Contoso.
Если вы столкнулись с проблемами, для их решения можно попробовать сравнить свой код с кодом готового проекта. Список распространенных ошибок и способы их устранения см. в разделе "Устранение неполадок" последнего руководства серии. Если вы не найдете, что вам нужно, вы можете отправить вопрос, чтобы StackOverflow.com для ASP.NET Core или EF Core.
Совет
Эта серия включает в себя 10 учебников, содержание каждого из которых базируется на предыдущих учебниках. После успешного завершения каждого руководства рекомендуется сохранять копию проекта. Таким образом, при возникновении проблем вы сможете вернуться к предыдущему учебнику, а не к началу серии.
В рамках этих учебников вы будете создавать приложение, которое представляет собой простой веб-сайт университета.
Пользователи приложения могут просматривать и обновлять сведения об учащихся, курсах и преподавателях. Будет создано несколько экранов.
Откройте Visual Studio.
В меню Файл выберите пункт Создать > Проект.
В области слева выберите Установленные > Visual C# > Интернет.
Выберите шаблон проекта Веб-приложение ASP.NET Core.
Введите имя ContosoUniversity и нажмите кнопку ОК.
Дождитесь появления диалогового окна Создание веб-приложения ASP.NET Core.
Выберите .NET Core, ASP.NET Core 2.2 и шаблон Веб-приложение (модель — представление — контроллер).
Убедитесь, что для параметра Проверка подлинности задано значение Без проверки подлинности.
Выберите ОК
Несколько простых изменений настраивают меню сайта, макет и домашнюю страницу.
Откройте Views/Shared/_Layout.cshtml
и внесите следующие изменения.
Замените все вхождения "ContosoUniversity" на "Contoso University". Таких элементов будет три.
Добавьте пункты меню About (Сведения), Students (Учащиеся), Courses (Курсы), Instructors (Преподаватели) и Departments (Кафедры). Удалите пункт меню Privacy.
Изменения выделены.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
crossorigin="anonymous"
integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
</environment>
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<partial name="_CookieConsentPartial" />
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"
asp-fallback-src="~/lib/jquery/dist/jquery.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
</script>
</environment>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
Замените содержимое файла Views/Home/Index.cshtml
следующим кодом, который заменяет текст об ASP.NET и MVC на текст о текущем приложении:
@{
ViewData["Title"] = "Home Page";
}
<div class="jumbotron">
<h1>Contoso University</h1>
</div>
<div class="row">
<div class="col-md-4">
<h2>Welcome to Contoso University</h2>
<p>
Contoso University is a sample application that
demonstrates how to use Entity Framework Core in an
ASP.NET Core MVC web application.
</p>
</div>
<div class="col-md-4">
<h2>Build it from scratch</h2>
<p>You can build the application by following the steps in a series of tutorials.</p>
<p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial »</a></p>
</div>
<div class="col-md-4">
<h2>Download it</h2>
<p>You can download the completed project from GitHub.</p>
<p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code »</a></p>
</div>
</div>
Нажмите клавиши CTRL+F5, чтобы запустить проект, и выберите в меню Отладка > Запуск без отладки. Вы увидите домашнюю страницу со вкладками для страниц, которые вы создадите в этих руководствах.
Чтобы добавить EF Core поддержку в проект, установите поставщик базы данных, который вы хотите нацелить. В этом учебнике используется SQL Server, для которого требуется пакет поставщика Microsoft.EntityFrameworkCore.SqlServer. Этот пакет входит в метапакет Microsoft.AspNetCore.App, поэтому ссылаться на него не нужно.
Этот пакет EF SQL Server и его зависимости (Microsoft.EntityFrameworkCore
и Microsoft.EntityFrameworkCore.Relational
) обеспечивают поддержку среды выполнения для платформы EF. Пакет средств будет добавлен позднее в рамках учебника Миграции.
Дополнительные сведения о других поставщиках баз данных, которые доступны для платформы Entity Framework Core, см. в разделе Поставщики баз данных.
Теперь необходимо создать классы сущностей для приложения университета Contoso. Для начала создаются следующие три сущности.
Между сущностями Student
и Enrollment
, а также между сущностями Course
и Enrollment
существует отношение "один ко многим". Другими словами, учащийся может быть зарегистрирован в любом количестве курсов, а в отдельном курсе может быть зарегистрировано любое количество учащихся.
В следующих разделах создаются классы для каждой из этих сущностей.
В папке Models создайте файл класса с именем Student.cs
и замените код шаблона следующим кодом.
using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
}
Свойство ID
будет использоваться в качестве столбца первичного ключа в таблице базы данных, соответствующей этому классу. По умолчанию платформа Entity Framework интерпретирует в качестве первичного ключа свойство ID
или classnameID
.
Свойство Enrollments
является свойством навигации. Свойства навигации содержат другие сущности, связанные с этой сущностью. В этом случае свойство Enrollments
сущности Student entity
содержит все сущности Enrollment
, которые связаны с этой сущностью Student
. Другими словами, если со строкой Student
в базе данных связаны две строки Enrollment
(строки, в столбце внешнего ключа StudentID которых содержится первичный ключ этого учащегося), в этой сущности Student
свойство навигации Enrollments
будет содержать две этих сущности Enrollment
.
Если свойство навигации может содержать несколько сущностей (как в отношениях "многие ко многим" или "один ко многим"), оно должно иметь тип списка, допускающий добавление, удаление и обновление записей, такой как ICollection<T>
. Вы можете указать тип ICollection<T>
либо, например, тип List<T>
или HashSet<T>
. Если указан тип ICollection<T>
, платформа EF по умолчанию создает коллекцию HashSet<T>
.
В папке 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 Course Course { get; set; }
public Student Student { get; set; }
}
}
Свойство EnrollmentID
будет использоваться в качестве первичного ключа. В этой сущности используется шаблон classnameID
вместо ID
, как в сущности Student
. Как правило, следует выбирать один шаблон, который будет использоваться в рамках всей модели данных. В этом случае демонстрируется возможность использования любого из шаблонов. В одном из следующих учебников вы узнаете, за счет чего использование идентификатора без имени класса позволяет упростить реализацию наследования в модели данных.
Свойство Grade
имеет тип enum
. Знак вопроса после объявления типа Grade
указывает, что свойство Grade
допускает значение null. Оценка со значением null отличается от нулевой оценки тем, что при таком значении оценка еще не известна или не назначена.
Свойство StudentID
представляет собой внешний ключ. Ему соответствует свойство навигации Student
. Сущность Enrollment
связана с одной сущностью Student
, поэтому это свойство может содержать одну сущность Student
(в отличие от представленного ранее свойства навигации Student.Enrollments
, которое может содержать несколько сущностей Enrollment
).
Свойство CourseID
представляет собой внешний ключ. Ему соответствует свойство навигации Course
. Сущность Enrollment
связана с одной сущностью Course
.
Платформа Entity Framework интерпретирует свойство как свойство внешнего ключа, если оно имеет имя <navigation property name><primary key property name>
(например, StudentID
для свойства навигации Student
, поскольку сущность Student
имеет первичный ключ ID
). Свойства внешнего ключа также могут называться просто <primary key property name>
(например CourseID
, поскольку сущность Course
имеет первичный ключ CourseID
).
В папке 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 ICollection<Enrollment> Enrollments { get; set; }
}
}
Свойство Enrollments
является свойством навигации. Сущность Course
может быть связана с любым числом сущностей Enrollment
.
Более подробное описание атрибута DatabaseGenerated
будет приведено в одном из следующих учебников этой серии. Фактически, этот атрибут позволяет ввести первичный ключ для курса, а не использовать базу данных, чтобы создать его.
Контекст базы данных — это основной класс, который координирует функциональные возможности Entity Framework для заданной модели данных. Этот класс создается путем наследования от класса Microsoft.EntityFrameworkCore.DbContext
. В коде указываются сущности, которые включаются в модель данных. Также вы можете настроить реакцию платформы Entity Framework на некоторые события. В этом проекте соответствующий класс называется SchoolContext
.
В папке проекта создайте папку Data.
В папке данных создайте файл класса с именем SchoolContext.cs
и замените код шаблона следующим кодом:
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
}
}
Этот код создает свойство DbSet
для каждого набора сущностей. В терминологии Entity Framework набор сущностей обычно соответствует таблице базы данных, а сущность — строке в этой таблице.
Вы можете опустить инструкции DbSet<Enrollment>
и DbSet<Course>
. Это не нарушит функциональность. Платформа Entity Framework включает эти инструкции неявно, поскольку сущность Student
ссылается на сущность Enrollment
, а Enrollment
ссылается на сущность Course
.
При создании базы данных платформа EF создает таблицы с именами, соответствующими именам свойств в DbSet
. Имена свойств для коллекций, как правило, задаются во множественном числе (например, Students вместо Student), однако единого мнения по поводу присвоения имен во множественном числе таблицам среди разработчиков не существует. В этих учебниках вместо принятого по умолчанию способа таблицам в DbContext присваиваются имена в единственном числе. Чтобы сделать это, добавьте выделенный ниже код после последнего свойства DbSet.
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
Выполните сборку проекта, чтобы проверить его на ошибки компиляции.
ASP.NET Core по умолчанию реализует технологию внедрения зависимостей. С помощью внедрения зависимостей службы (например, контекст базы данных EF) регистрируются во время запуска приложения. Затем компоненты, которые используют эти службы (например, контроллеры MVC), обращаются к ним через параметры конструктора. Код конструктора контроллера, который получает экземпляр контекста, будет приведен позднее в этом учебнике.
Чтобы зарегистрировать SchoolContext
как службу, откройте файл Startup.cs
и добавьте выделенные строки в метод ConfigureServices
.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
}
Имя строки подключения передается в контекст путем вызова метода для объекта DbContextOptionsBuilder
. При локальной разработке система конфигурации ASP.NET Core считывает строку подключения из файла appsettings.json
.
Добавьте инструкции using
для пространств имен ContosoUniversity.Data
и Microsoft.EntityFrameworkCore
, после чего выполните построение проекта.
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;
Откройте файл appsettings.json
и добавьте строку подключения, как показано в следующем примере.
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Строка подключения указывает на базу данных SQL Server LocalDB. LocalDB — это упрощенная версия ядра СУБД SQL Server Express, предназначенная для разработки приложений и не ориентированная на использование в производственной среде. LocalDB запускается по запросу в пользовательском режиме, поэтому настройки не слишком сложны. По умолчанию база данных LocalDB создает файлы .mdf в каталоге C:/Users/<user>
.
Платформа Entity Framework создает пустую базу данных. В этом разделе вы напишете метод, который вызывается после создания базы данных и заполняет ее тестовыми данными.
Здесь будет использоваться метод EnsureCreated
для автоматического создания базы данных. В одном из следующих учебников вы узнаете, как обрабатывать изменения модели с использованием Code First Migrations, что позволяет изменять схему базы данных вместо того, чтобы удалять и повторно создавать ее.
В папке данных создайте новый файл класса с именем DbInitializer.cs
и замените код шаблона следующим кодом, что приводит к созданию базы данных при необходимости и загрузке тестовых данных в новую базу данных.
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
context.Database.EnsureCreated();
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
};
foreach (Student s in students)
{
context.Students.Add(s);
}
context.SaveChanges();
var courses = new 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}
};
foreach (Course c in courses)
{
context.Courses.Add(c);
}
context.SaveChanges();
var enrollments = new Enrollment[]
{
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
};
foreach (Enrollment e in enrollments)
{
context.Enrollments.Add(e);
}
context.SaveChanges();
}
}
}
Этот код проверяет, добавлены ли в базу данных учащиеся. Если нет, база данных считается новой и заполняется тестовыми данными. Для повышения производительности тестовые данные загружаются массивами, а не коллекциями List<T>
.
В файле Program.cs
измените метод Main
, чтобы реализовать следующее поведение при запуске приложения:
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
При первом запуске приложения будет создана и заполнена тестовыми данными необходимая для работы база данных. При каждом изменении модели данных:
В следующих учебниках вы узнаете, как изменить базу данных при изменении модели данных, не прибегая к ее удалению и повторному созданию.
В этом разделе подсистема формирования шаблонов Visual Studio используется для добавления контроллера и представлений MVC, которые будут использовать платформу EF для запроса данных и их сохранения.
Автоматическое создание методов и представлений операций CRUD (создание, чтение, обновление и удаление) называется формированием шаблонов. Формирование шаблонов отличается от создания кода тем, что шаблонный код является отправной точкой и может изменяться в соответствии с потребностями, тогда как сформированный код обычно не изменяется. В тех случаях, когда требуется настроить созданный код в соответствии с внесенными изменениями, вы можете использовать разделяемые классы или повторно создать код.
Подсистема формирования шаблонов Visual Studio создает файл StudentsController.cs
и набор представлений (файлы .cshtml
), которые будут работать с контроллером.
Обратите внимание, что контроллер принимает SchoolContext
в качестве параметра конструктора.
namespace ContosoUniversity.Controllers
{
public class StudentsController : Controller
{
private readonly SchoolContext _context;
public StudentsController(SchoolContext context)
{
_context = context;
}
Технология внедрения зависимостей ASP.NET Core обеспечивает передачу экземпляра SchoolContext
в контроллер. Это было настроено в файле Startup.cs
.
Контроллер содержит метод действия Index
, который отображает всех учащихся в базе данных. Этот метод получает список учащихся из набора сущностей Students, считывая свойство Students
экземпляра контекста базы данных:
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
Позднее в этом учебнике будут описаны элементы асинхронного программирования в этом коде.
В Views/Students/Index.cshtml
представлении отображается этот список в таблице:
@model IEnumerable<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<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>
</thead>
<tbody>
@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>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Нажмите клавиши CTRL+F5, чтобы запустить проект, и выберите в меню Отладка > Запуск без отладки.
Перейдите на вкладку Students (Учащиеся), чтобы просмотреть тестовые данные, добавленные методом DbInitializer.Initialize
. В зависимости от размеров окна браузера ссылку на вкладку Students
можно найти вверху страницы или щелкнув значок навигации в правом верхнем углу.
При запуске приложения метод DbInitializer.Initialize
вызывает метод EnsureCreated
. Платформа EF определяет, что база данных отсутствует, и создает ее, после чего код в оставшейся части метода Initialize
заполняет базу данными. Для просмотра базы данных в Visual Studio можно использовать обозреватель объектов SQL Server (SSOX).
Закройте браузер.
Если окно SSOX не открылось, выберите его в меню Вид Visual Studio.
В окне SSOX щелкните (localdb)\MSSQLLocalDB > Базы данных, а затем щелкните запись базы данных, имя которой указано в строке подключения в вашем файле appsettings.json
.
Разверните узел Таблицы, чтобы просмотреть представленные в базе таблицы.
Щелкните правой кнопкой мыши таблицу Student и выберите пункт Просмотр данных, чтобы просмотреть созданные столбцы и строки, вставленные в базу данных.
Файлы базы данных с расширениями MDF и LDF находятся в папке C:\Users\<имя_пользователя>.
Поскольку вы вызываете метод EnsureCreated
в методе инициализатора, который выполняется при запуске приложения, теперь вы можете внести изменения в класс Student
, удалить базу данных и снова запустить приложение. После этого база данных будет создана повторно в соответствии с внесенными изменениями. Например, при добавлении свойства EmailAddress
в класс Student
во вновь созданной таблице появится столбец EmailAddress
.
Чтобы платформа Entity Framework автоматически создавала полную базу данных на основе принятых соглашений и допущений, потребуется написать минимальный объем кода.
DbSet
. Для сущностей, на которые не ссылается свойство DbSet
, в качестве имен таблиц используются имена классов сущностей.StudentID
для свойства навигации Student
, так как сущность Student
имеет первичный ключ ID
). Свойства внешнего ключа также могут называться просто <имя_свойства_первичного_ключа> (например EnrollmentID
, так как сущность Enrollment
имеет первичный ключ EnrollmentID
).Стандартное поведение можно переопределить. Например, можно явно задать имена таблиц, как было показано ранее в этом учебнике. Также можно указать имена столбцов и задать любое свойство в качестве первичного или внешнего ключа, как будет показано в одном из следующих учебников этой серии.
Асинхронное программирование — это режим по умолчанию для ASP.NET Core и EF Core.
Веб-сервер имеет ограниченное число потоков, поэтому при высокой загрузке могут использоваться все доступные потоки. В таких случаях сервер не может обрабатывать новые запросы до тех пор, пока не будут высвобождены потоки. В синхронном коде многие потоки могут быть заняты, не выполняя при этом какие-либо операции и ожидая завершения ввода-вывода. В асинхронном коде в то время, когда процесс ожидает завершения ввода-вывода, его поток высвобождается и может использоваться сервером для обработки других запросов. Таким образом, асинхронный код позволяет более эффективно использовать ресурсы сервера, который может обрабатывать больше трафика без задержек.
Во время выполнения асинхронный код использует немного больше служебных ресурсов, однако при низком объеме трафика этим можно пренебречь. Тем не менее в случае большого объема трафика это дает существенный выигрыш в производительности.
В следующем коде для асинхронного выполнения используются ключевое слово async
, возвращаемое значение Task<T>
, ключевое слово await
и метод ToListAsync
.
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
async
указывает компилятору создавать обратные вызовы для частей тела метода и автоматически создавать возвращаемый объект Task<IActionResult>
.Task<IActionResult>
представляет текущую операцию с помощью результата типа IActionResult
.await
предписывает компилятору разделить метод на две части. Первая часть завершается операцией, которая запускается в асинхронном режиме. Вторая часть помещается в метод обратного вызова, который вызывается при завершении операции.ToListAsync
является асинхронной версией метода расширения ToList
.При написании асинхронного кода, который использует Entity Framework, необходимо учитывать некоторые моменты:
ToListAsync
, SingleOrDefaultAsync
и SaveChangesAsync
. В их число не входят, например, инструкции, которые просто изменяют IQueryable
, такие как var students = context.Students.Where(s => s.LastName == "Davolio")
.await
.Дополнительные сведения об асинхронных методах программирования в .NET см. в разделе Обзор асинхронной модели.
В следующем учебнике описано, как выполнять основные операции CRUD (создание, чтение, обновление и удаление).
Отзыв о ASP.NET Core
ASP.NET Core — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
События
Присоединение к вызову ИИ Навыков
8 апр., 15 - 28 мая, 07
Отточите свои навыки ИИ и введите подметки, чтобы выиграть бесплатный экзамен сертификации
Зарегистрируйтесь!