Asp.Net Core MVC CRUD с EF Core
Создание , получение , обновление и удаление [CRUD] — основные операции в любом приложении. Приложения без какой-либо из этих операций были бы редки. В этой статье мы реализуем операции CRUD в приложении ASP.NET Core MVC с помощью Entity Framework Core — подход Code First. Чтобы продемонстрировать тему, мы создадим приложение для хранения и управления данными о сотрудниках.
Репозиторий GitHub для демонстрационного проекта: https://goo.gl/E13H2R
Создать проект ASP.NET Core MVC
В Visual Studio выберите «Файл» > «Создать» > «Проект» (Ctrl + Shift + N). Затем выберите веб-приложение ASP.NET Core.
В мастере шаблонов выберите шаблон веб-приложения (MVC). Обязательно выберите последнюю версию ASP.NET Core в верхнем раскрывающемся списке. Снимите флажок HTTPS, который не требуется в среде разработки.
Настройка базы данных для EF Core
База данных для проекта будет создаваться и управляться с помощью EF Core — Code First Approach. Итак, прежде всего, мы должны установить соответствующие пакеты NuGet. Щелкните проект правой кнопкой мыши в обозревателе решений и выберите Управление пакетами NuGet. На вкладке обзора найдите и установите Microsoft.EntityFrameworkCore
и зависимые от него пакеты.
Теперь давайте определим класс модели для сущности сотрудника в Models
папке как Employee
.
//File : /Models/Employee.cs
public class Employee
{
[Key]
public int EmployeeId { get; set; }
[Column(TypeName ="nvarchar(250)")]
[Required(ErrorMessage ="This field is required.")]
[DisplayName("Full Name")]
public string FullName { get; set; }
[Column(TypeName = "varchar(10)")]
[DisplayName("Emp. Code")]
public string EmpCode { get; set; }
[Column(TypeName = "varchar(100)")]
public string Position { get; set; }
[Column(TypeName = "varchar(100)")]
[DisplayName("Office Location")]
public string OfficeLocation { get; set; }
}
В Entity Framework фактические физические объекты в базе данных создаются и управляются из класса DBContext. В нашем приложении EmployeeContext
всю работу выполняет класс. Чтобы создать таблицу, соответствующую классу модели сотрудника, мы добавили Employees
свойство типа DbSet
.
//File : /Models/EmployeeContext.cs
public class EmployeeContext:DbContext
{
public EmployeeContext(DbContextOptions<EmployeeContext> options):base(options)
{ }
public DbSet<Employee> Employees { get; set; }
}
Внедрить класс DbContext с внедрением зависимостей.
Для взаимодействия с базой данных нам нужен экземпляр класса DbContext
. Мы можем сделать это с помощью внедрения зависимостей. Для параметра конструктора класса options
требуется следующая информация.
- Поставщик базы данных — будь то SQL Server, MySQL, PostgreSQL и т. д.
- Строка подключения к БД
Прежде всего, мы сохраним строку подключения в appsettings.json
файле следующим образом.
{
...,
"ConnectionStrings": {
"DevConnection": "Server=(local)\\sqlexpress;Database=EmployeeDB;Trusted_Connection=True;MultipleActiveResultSets=True;"
}
}
Теперь давайте создадим DbContext
экземпляр, передав строку подключения к БД и поставщика БД, используя внедрение зависимостей из Asp.Net Core. Для этого нам просто нужно обновить ConfigureServices
метод из Startup
класса. Вызовите AddDbConext
метод из services
коллекции следующим образом.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDbContext<EmployeeContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
}
Как и когда работает эта инъекция зависимостей? мы обсудим это позже, как только мы добавим контроллер сотрудников в этот проект.
Инициировать миграцию БД
До сих пор мы моделировали нашу базу данных, давайте создадим фактическую базу данных. Прежде всего, откройте консоль диспетчера пакетов. Для этого вы можете щелкнуть правой кнопкой мыши проект в обозревателе решений, а затем перейти в «Инструменты» > «Диспетчер пакетов NuGet» > «Консоль диспетчера пакетов». Внутри консоли выполните следующие команды одну за другой.
Add-Migration "InitialCreate"
Update-Database
Теперь у вас должна быть база данных EmployeeDB (упомянутая в строке подключения), созданная в соответствии с нашей моделью сотрудника.
Создайте контроллер MVC для операций CRUD
Давайте создадим новый контроллер MVC EmployeeController
. Перейдите в «Контроллер» > «Добавить» > «Контроллер», затем выберите «Контроллер MVC с представлениями, используя шаблон Entity Framework». Выберите Employee
и EmployeeContext
в качестве класса Model и DbContext соответственно.
Созданный контроллер MVC будет иметь все методы действий для всех операций CRUD, хотя я хотел бы упростить его следующим образом. Каждый из методов действия будет рассмотрен далее в этой статье.
public class EmployeeController : Controller
{
private readonly EmployeeContext _context;
//constructor
public EmployeeController(EmployeeContext context)
{
_context = context;
}
// GET: Employee
public async Task<IActionResult> Index()
{ ... }
// GET: Employee/AddOrEdit
public IActionResult AddOrEdit(int id = 0)
{ ... }
// POST: Employee/AddOrEdit
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddOrEdit([Bind("EmployeeId,FullName,EmpCode,Position,OfficeLocation")] Employee employee)
{ ... }
// GET: Employee/Delete/5
public async Task<IActionResult> Delete(int? id)
{ ... }
}
Теперь несколько слов о внедрении зависимостей ASP.NET Core: Как вы знаете, экземпляр контроллера MVC будет создан после того, как к нему будет сделан запрос. Но есть параметр конструктора context
типа EmployeeContext
. Как мы можем передать значение для параметра, когда экземпляр контроллера создается самой платформой ASP.NET Core? Здесь возникает важность внедрения зависимостей, которое мы настроили выше в Startup
классе, всякий раз, когда конструктору контроллера требуется экземпляр DbContext
, внедрение зависимостей передает экземпляр. Таким образом, остальные методы действий внутри контроллера могут взаимодействовать с базой данных через внедренный DbContext
экземпляр.
Получить список записей в представлении MVC
Назначение каждого метода действия в EmployeeController
.
Index
: Получить список записей из таблицы сотрудников.AddOrEdit
: Обработка операций вставки и обновления.Delete
: удалить запись о сотруднике с заданным идентификатором сотрудника.
Все вышеперечисленные методы действия либо манипулируют данными, либо извлекают существующие данные из базы данных. Теперь нам нужно спроектировать пользовательский интерфейс с бритвенными представлениями для отображения полученных данных или формой/кнопкой для отправки данных в методы действия. Вы могли видеть такие бритвенные взгляды в /Views/Employee
папке.
Теперь давайте получим список сотрудников, используя Index
метод действия.
// GET: Employees
public async Task<IActionResult> Index()
{
return View(await _context.Employees.ToListAsync());
}
Список записей из таблицы сотрудников можно легко получить с помощью DbSet
свойства Employees
, как показано выше. Коллекция записей возвращается функцией View
. Таким образом, должен быть файл представления бритвы index.cshtml
(то же имя, что и у метода действия индекса) для отображения коллекции записей. Мы сделали это с помощью таблицы HTML, используя foreach
цикл.
@model IEnumerable<Asp.netCoreMVCCRUD.Models.Employee>
@{
ViewData["Title"] = "Index";
}
<h4>Employee Register</h4>
<hr />
<table class="table table-hover">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FullName)
</th>
<th>
@Html.DisplayNameFor(model => model.EmpCode)
</th>
<th>
@Html.DisplayNameFor(model => model.Position)
</th>
<th>
@Html.DisplayNameFor(model => model.OfficeLocation)
</th>
<th>
<a asp-action="AddOrEdit" class="btn btn-outline-success"><i class="far fa-plus-square"></i> Employee</a>
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.FullName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EmpCode)
</td>
<td>
@Html.DisplayFor(modelItem => item.Position)
</td>
<td>
@Html.DisplayFor(modelItem => item.OfficeLocation)
</td>
<td>
<a asp-action="AddOrEdit" asp-route-id="@item.EmployeeId"><i class="fa fa-marker fa-lg"></i></a>
<a asp-action="Delete" asp-route-id="@item.EmployeeId" class="text-danger ml-1" onclick="return confirm('Are you sure to delete this record?')"><i class="fa fa-trash-alt fa-lg"></i></a>
</td>
</tr>
}
</tbody>
</table>
Новый сотрудник может быть вставлен с помощью кнопки + из заголовка последнего столбца. Последний столбец содержит кнопки для редактирования/обновления и операции удаления. Теперь индексное представление должно выглядеть так.
Вы видели здесь навигатор? внутри нашего бритвенного представления мы только сказали показать HTML-таблицу, откуда же взялась эта навигационная панель? Это из нашего глобального представления макета Shared/_Layout.cshtml
. Не только панель навигации, но и все HTML-объявление, а также окружающие его теги body и head определяются в этом представлении макета. Таким образом, по умолчанию в любом проекте MVC будет заключен весь файл представлений. К нему следует добавить ссылку на таблицы стилей для Bootstrap и Font Awesome. В большинстве случаев Bootstrap уже будет там, просто добавьте ссылку на таблицу стилей Font Awesome.
<!-- Add following stylesheets to <head> tag -->
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css" data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" onerror="this.removeAttribute('data-rocket-async')" />
Добавить или изменить запись
Обычно по умолчанию будут отдельные методы для операций вставки и обновления. здесь, в этом проекте, мы объединили их в один. Прежде всего, давайте определим GET
и POST
методы для операций вставки и обновления с AddOrEdit
методом действия.
// GET: Employee/AddOrEdit
public IActionResult AddOrEdit(int id = 0)
{
if (id == 0)
return View(new Employee());
else
return View(_context.Employees.Find(id));
}
// POST: Employee/AddOrEdit
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddOrEdit([Bind("EmployeeId,FullName,EmpCode,Position,OfficeLocation")] Employee employee)
{
if (ModelState.IsValid)
{
if (employee.EmployeeId == 0)
_context.Add(employee);
else
_context.Update(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
А вот наш AddOrEdit.cshtml
взгляд на описанный выше GET
метод действия.
@model Asp.netCoreMVCCRUD.Models.Employee
@{
ViewData["Title"] = "Create";
}
<h4>Employee Form</h4>
<hr />
<div class="row">
<div class="col-md-6">
<form asp-action="AddOrEdit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="EmployeeId" />
<div class="form-group">
<label asp-for="FullName" class="control-label"></label>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label asp-for="EmpCode" class="control-label"></label>
<input asp-for="EmpCode" class="form-control" />
<span asp-validation-for="EmpCode" class="text-danger"></span>
</div>
<div class="form-group col-md-6">
<label asp-for="Position" class="control-label"></label>
<input asp-for="Position" class="form-control" />
<span asp-validation-for="Position" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="OfficeLocation" class="control-label"></label>
<input asp-for="OfficeLocation" class="form-control" />
<span asp-validation-for="OfficeLocation" class="text-danger"></span>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<input type="submit" value="Submit" class="btn btn-primary btn-block" />
</div>
<div class="form-group col-md-6">
<a asp-action="Index" class="btn btn-secondary btn-block"><i class="fa fa-table"></i> Back to List</a>
</div>
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Это представление возвращается AddOrEdit
методом действия типа GET
. Метод возвращает свежий экземпляр модели сотрудника, если id
параметр равен 0
. id
В противном случае возвращается соответствующая запись сотрудника с данным . Наконец, возвращенная модель заполняется внутри AdddOrEdit.cshtml
представления. Для операции вставки форма выглядит следующим образом.
Эта форма будет отправлена AddOrEdit
методом действия Post. Мы обработали обе операции внутри блока if-else на основе значения id
параметра. Нам просто нужно вызвать Add
или Update
метод из DbContext
объекта для операций вставки и обновления соответственно. В конце концов, вызовите метод Entity Framework SaveChangesAsync
. Если операция прошла успешно, мы будем перенаправлены на Index
метод действия, чтобы вернуть список записей с последней модификацией.
Проверка формы
Внутри нашей Employee
модели мы определили FullName
свойство с Required
атрибутом, что означает, что свойство должно содержать значение перед отправкой вышеуказанной формы. Entity Framework Core Validation поддерживает множество подобных атрибутов. Мы проверили статус проверки модели в GET
методе действия AddOrEdit
со ModelState.IsValid
свойством.
Если есть какая-либо ошибка проверки, та же форма возвращается с той же моделью, обновленной с сообщением об ошибке проверки.
Удалить запись
Вы можете удалить запись с помощью кнопки удаления из представления индекса, она будет обрабатываться в Delete
методе действия.
// GET: Employee/Delete/5
public async Task<IActionResult> Delete(int? id)
{
var employee =await _context.Employees.FindAsync(id);
_context.Employees.Remove(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Внутри метода FindAsync
извлекает соответствующую запись с заданной id
переменной employee
, а затем вызывает Remove
метод из Employees
свойства DbSet. и не забудьте вызвать SaveChangesAsync
метод, который выполняет соответствующие команды SQL в серверной части SQL Server Engine.
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.