Руководство. Использование асинхронных и хранимых процедур с EF в приложении MVC ASP.NET
В предыдущих руководствах вы узнали, как считывать и обновлять данные с помощью синхронной модели программирования. В этом руководстве описано, как реализовать асинхронную модель программирования. Асинхронный код может помочь приложению повысить производительность, так как он лучше использует серверные ресурсы.
В этом руководстве вы также узнаете, как использовать хранимые процедуры для операций вставки, обновления и удаления для сущности.
Наконец, вы повторно развернете приложение в Azure вместе со всеми изменениями базы данных, реализованными с момента первого развертывания.
На следующих рисунках изображены некоторые из страниц, с которыми вы будете работать.
Изучив это руководство, вы:
- Сведения об асинхронном коде
- Создание контроллера отдела
- Использование хранимых процедур
- Развернуть в Azure
Предварительные требования
Зачем использовать асинхронный код
Веб-сервер имеет ограниченное число потоков, поэтому при высокой загрузке могут использоваться все доступные потоки. В таких случаях сервер не может обрабатывать новые запросы до тех пор, пока не будут высвобождены потоки. В синхронном коде многие потоки могут быть заняты, не выполняя при этом какие-либо операции и ожидая завершения ввода-вывода. В асинхронном коде в то время, когда процесс ожидает завершения ввода-вывода, его поток высвобождается и может использоваться сервером для обработки других запросов. В результате асинхронный код позволяет более эффективно использовать ресурсы сервера, а сервер может обрабатывать больше трафика без задержек.
В более ранних версиях .NET написание и тестирование асинхронного кода было сложным, подверженным ошибкам и трудным для отладки. В .NET 4.5 написание, тестирование и отладка асинхронного кода гораздо проще, что обычно следует писать асинхронный код, если нет причин. Асинхронный код приводит к небольшим издержкам, но для ситуаций с низким трафиком снижение производительности незначительно, а для ситуаций с большим трафиком потенциальное повышение производительности существенно.
Дополнительные сведения об асинхронном программировании см. в статье Использование асинхронной поддержки .NET 4.5 во избежание блокировки вызовов.
Создание контроллера отдела
Создайте контроллер отдела так же, как и предыдущие контроллеры, за исключением того, что на этот раз установите флажок Использовать действия асинхронного контроллера проверка.
Ниже показано, что было добавлено в синхронный код метода, Index
чтобы сделать его асинхронным.
public async Task<ActionResult> Index()
{
var departments = db.Departments.Include(d => d.Administrator);
return View(await departments.ToListAsync());
}
Для асинхронного выполнения запроса к базе данных Entity Framework были применены четыре изменения:
- Метод помечается
async
ключевое слово, который указывает компилятору создавать обратные вызовы для частей тела метода и автоматически создаватьTask<ActionResult>
возвращаемый объект. - Тип возвращаемого значения изменен с
ActionResult
наTask<ActionResult>
. ТипTask<T>
представляет текущую работу с результатом типаT
. - Ключевое слово
await
была применена к вызову веб-службы. Когда компилятор видит этот ключевое слово, он разделяет метод на две части. Первая часть завершается операцией, которая запускается асинхронно. Вторая часть помещается в метод обратного вызова, который вызывается по завершении операции. - Была вызвана
ToList
асинхронная версия метода расширения.
Почему изменяется оператор , departments.ToList
а не departments = db.Departments
оператор? Причина заключается в том, что асинхронно выполняются только инструкции, вызывающие отправку запросов или команд в базу данных. Инструкция departments = db.Departments
настраивает запрос, но запрос не выполняется до ToList
вызова метода . Поэтому асинхронно выполняется только ToList
метод .
В методе Details
иEdit
HttpGet
и Delete
метод является методом, Find
который вызывает отправку запроса в базу данных, поэтому этот метод выполняется асинхронно:
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Department department = await db.Departments.FindAsync(id);
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
В методах Create
, HttpPost Edit
и DeleteConfirmed
вызывается SaveChanges
вызов метода, который вызывает выполнение команды, а не инструкции, такие как db.Departments.Add(department)
, которые вызывают изменение только сущностей в памяти.
public async Task<ActionResult> Create(Department department)
{
if (ModelState.IsValid)
{
db.Departments.Add(department);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
Откройте файл Views\Department\Index.cshtml и замените код шаблона следующим кодом:
@model IEnumerable<ContosoUniversity.Models.Department>
@{
ViewBag.Title = "Departments";
}
<h2>Departments</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Budget)
</th>
<th>
@Html.DisplayNameFor(model => model.StartDate)
</th>
<th>
Administrator
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Budget)
</td>
<td>
@Html.DisplayFor(modelItem => item.StartDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Administrator.FullName)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
@Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
</td>
</tr>
}
</table>
Этот код изменяет заголовок с Индекс на Отделы, перемещает имя администратора вправо и предоставляет полное имя администратора.
В представлениях Создание, Удаление, Сведения и Изменение измените подпись поля на InstructorID
"Администратор" так же, как вы изменили поле названия отдела на "Отдел" в представлениях курса.
В представлениях Создание и Изменение используйте следующий код:
<label class="control-label col-md-2" for="InstructorID">Administrator</label>
В представлениях Удалить и Сведения используйте следующий код:
<dt>
Administrator
</dt>
Запустите приложение и перейдите на вкладку Отделы .
Все работает так же, как и в других контроллерах, но в этом контроллере все SQL-запросы выполняются асинхронно.
При использовании асинхронного программирования с Entity Framework необходимо учитывать следующее:
- Асинхронный код не является потокобезопасной. Иными словами, не пытайтесь выполнять несколько операций параллельно, используя один и тот же экземпляр контекста.
- Если вы хотите использовать преимущества в производительности, которые обеспечивает асинхронный код, убедитесь, что все используемые пакеты библиотек (например, для разбиения на страницы) также используют асинхронный код при вызове любых методов Entity Framework, выполняющих запросы к базе данных.
Использование хранимых процедур
Некоторые разработчики и администраторы баз данных предпочитают использовать хранимые процедуры для доступа к базе данных. В более ранних версиях Entity Framework можно было получить данные с помощью хранимой процедуры, выполнив необработанный SQL-запрос, но вы не можете указать EF использовать хранимые процедуры для операций обновления. В EF 6 легко настроить Code First для использования хранимых процедур.
В файле DAL\SchoolContext.cs добавьте выделенный код в
OnModelCreating
метод .protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Entity<Course>() .HasMany(c => c.Instructors).WithMany(i => i.Courses) .Map(t => t.MapLeftKey("CourseID") .MapRightKey("InstructorID") .ToTable("CourseInstructor")); modelBuilder.Entity<Department>().MapToStoredProcedures(); }
Этот код указывает Entity Framework использовать хранимые процедуры для операций вставки, обновления и удаления сущности
Department
.В консоли управления пакетами введите следующую команду:
add-migration DepartmentSP
Откройте файл Migrations\<timestamp>_DepartmentSP.cs , чтобы просмотреть код в методе
Up
, который создает хранимые процедуры вставки, обновления и удаления:public override void Up() { CreateStoredProcedure( "dbo.Department_Insert", p => new { Name = p.String(maxLength: 50), Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"), StartDate = p.DateTime(), InstructorID = p.Int(), }, body: @"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID]) VALUES (@Name, @Budget, @StartDate, @InstructorID) DECLARE @DepartmentID int SELECT @DepartmentID = [DepartmentID] FROM [dbo].[Department] WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity() SELECT t0.[DepartmentID] FROM [dbo].[Department] AS t0 WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID" ); CreateStoredProcedure( "dbo.Department_Update", p => new { DepartmentID = p.Int(), Name = p.String(maxLength: 50), Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"), StartDate = p.DateTime(), InstructorID = p.Int(), }, body: @"UPDATE [dbo].[Department] SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID WHERE ([DepartmentID] = @DepartmentID)" ); CreateStoredProcedure( "dbo.Department_Delete", p => new { DepartmentID = p.Int(), }, body: @"DELETE [dbo].[Department] WHERE ([DepartmentID] = @DepartmentID)" ); }
В консоли управления пакетами введите следующую команду:
update-database
Запустите приложение в режиме отладки, перейдите на вкладку Отделы и нажмите кнопку Создать.
Введите данные для нового отдела и нажмите кнопку Создать.
В Visual Studio просмотрите журналы в окне Вывод , чтобы увидеть, что для вставки новой строки Department использовалась хранимая процедура.
Code First создает имена хранимых процедур по умолчанию. Если вы используете существующую базу данных, может потребоваться настроить имена хранимых процедур, чтобы использовать хранимые процедуры, уже определенные в базе данных. Сведения о том, как это сделать, см. в статье Первая вставка, обновление и удаление хранимых процедур Entity Framework Code.
Если вы хотите настроить действия созданных хранимых процедур, можно изменить шаблонный код для метода миграции Up
, который создает хранимую процедуру. Таким образом, изменения отражаются при каждом выполнении миграции и будут применены к рабочей базе данных при автоматическом выполнении миграции в рабочей среде после развертывания.
Если вы хотите изменить существующую хранимую процедуру, созданную во время предыдущей миграции, можно использовать команду Add-Migration, чтобы создать пустую миграцию, а затем вручную написать код, который вызывает метод AlterStoredProcedure .
Развернуть в Azure
Для работы с этим разделом необходимо выполнить необязательное развертывание приложения в Azure в руководстве по миграциям и развертыванию этой серии. Если у вас были ошибки миграции, которые были устранены путем удаления базы данных в локальном проекте, пропустите этот раздел.
В Visual Studio щелкните правой кнопкой мыши проект в обозревателе решений и выберите Опубликовать в контекстном меню.
Нажмите кнопку Опубликовать.
Visual Studio развертывает приложение в Azure, и приложение откроется в браузере по умолчанию, работающем в Azure.
Протестируйте приложение, чтобы убедиться, что оно работает.
При первом запуске страницы, которая обращается к базе данных, Entity Framework выполняет все методы миграции, необходимые
Up
для обновления базы данных с текущей моделью данных. Теперь можно использовать все веб-страницы, добавленные с момента последнего развертывания, включая страницы отдела, добавленные в этом руководстве.
Получите код
Скачивание завершенного проекта
Дополнительные ресурсы
Ссылки на другие ресурсы Entity Framework можно найти в ASP.NET доступ к данным — рекомендуемые ресурсы.
Дальнейшие действия
Изучив это руководство, вы:
- Сведения об асинхронном коде
- Создание контроллера отдела
- Используемые хранимые процедуры
- Развертывание в Azure
Перейдите к следующей статье, чтобы узнать, как обрабатывать конфликты при одновременном обновлении одной сущности несколькими пользователями.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по