[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на C# станут решающим фактором. Переходите по ссылке 🔰.
У цій статті ми розглянемо приклад простого Asp.Net Mvc Crud додатка, у двох варіантах: з використанням EF Core і звичайної колекції.
Операції будуть засновані на моделі User, що представляє звичайного користувача.
Під час роботи з базою даних, очікую від вас мінімальні знання концепцій Entity Framework Core, тому в деяких місцях, вдаватися в подробиці не стану.
Додаток Asp.Net Mvc Crud
Створення та налаштування проекту
Додавання контролера та подання
Зберігання даних з Entity Framework Core
Створення та налаштування проекту
Щоб створити проект Users, запустіть Visual Studio і виберіть у меню File (Файл) – New Project (Створити Проект). Вкажіть шаблон проекту ASP.NET Core Web Application (Веб-додаток ASP.NET Core). Введіть UsersCrud, у полі Name, на наступній сторінці вкажіть Framework .Net 7.0 і натисніть кнопку Create:
Модель і Репозиторій
Модель для додатка UsersCrud буде заснована на списку користувачів. Створіть папку Models і додайте в неї файл класу на ім’я User.cs з таким вмістом:
1 2 3 4 5 6 7 |
public class User { public string Id { get; set; } = Guid.NewGuid().ToString(); public string Email { get; set; } public string? Name { get; set; } public int Age { get; set; } } |
Мені подобається забезпечувати узгоджений доступ до даних у застосунку з використанням патерну “Сховище” (Repository), у якому інтерфейс визначає властивості та методи, призначені для доступу до даних, а для роботи з механізмом зберігання даних застосовується клас реалізації. Перевага використання патерну “Сховище” пов’язана з полегшенням модульного тестування частини MVC додатка, а також із тим, що деталі, які стосуються зберігання даних, приховані від інших частин додатка.
Щоб створити інтерфейс сховища, створіть папку Interfaces і додайте в неї файл інтерфейсу на ім’я IUser.cs з таким вмістом:
1 2 3 4 5 6 7 8 9 |
public interface IUser { IEnumerable<User> GetAllUsers(); User GetUser(string id); void AddUser(User user); void UpdateUser(User user); void DeleteUser(string id); } |
Метод GetAllUsers() надаватиме доступ тільки для читання до всіх користувачів, відомих застосунку. Метод AddUser() буде використовуватися для додавання нових користувачів.
На цьому етапі ми збираємося зберігати об’єкти моделі в пам’яті, а трохи пізніше замінимо це інфраструктурою Entity Framework Core. Створіть папку Repository і додайте в неї файл класу на ім’я UserRepository.cs з таким вмістом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
public class UserRepository : IUser { private List<User> _users; public UserRepository() { _users = new List<User>() { new User { Name = "Alex", Age = 30, Email = "alex@gmail.com"}, new User { Name = "Marry", Age = 19, Email = "marry@gmail.com"}, new User { Name = "Tom", Age = 27, Email = "tom@gmail.com"}, new User { Name = "Karen", Age = 38, Email = "karen@gmail.com"}, new User { Name = "John", Age = 41, Email = "john@gmail.com"} }; } public void AddUser(User user) { user.Id = Guid.NewGuid().ToString(); _users.Add(user); } public void DeleteUser(string id) { _users.Remove(GetUser(id)); } public IEnumerable<User> GetAllUsers() { return _users; } public User GetUser(string id) { return _users.FirstOrDefault(e => e.Id.ToString().Equals(id)); } public void UpdateUser(User user) { var currentUser = _users.FirstOrDefault(e => e.Id.ToString().Equals(user.Id)); if (currentUser != null) { currentUser.Name = user.Name; currentUser.Email = user.Email; currentUser.Age = user.Age; } } } |
Клас UserRepository реалізує інтерфейс IUser і застосовує екземпляр List для відстеження об’єктів User, тобто в разі зупинки або перезапуску застосунку дані будуть втрачатися. Постійне сховище буде введено в пізніше, а сховища в пам’яті цілком достатньо для приведення в працездатний стан частини ASP.NET Core МVС проекту, перш ніж додавати частину EntityFramework Core.
Додайте в клас Program оператор наступний оператор, щоб зареєструвати клас UserRepository як реалізацію для використання в якості залежностей інтерфейсу IUser:
1 |
builder.Services.AddSingleton<IUser, UserRepository>(); |
Цей рядок коду реєструє клас UserRepository із застосуванням методу AddSingleton. У результаті під час розпізнавання залежності інтерфейсу IUser вперше створюється одиночний об’єкт, який буде використовуватися для всіх наступних залежностей.
Під час додавання і редагування користувачів нам необхідно зосередитися на процесі валідації моделі, для цього в корені проєкту визначимо папку ViewModels, до якої додамо клас UserViewModel з таким вмістом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class UserViewModel { [Key] public string? Id { get; set; } [Required] [DataType(DataType.EmailAddress)] public string? Email { get; set; } public string? Name { get; set; } [Required] [Range(10,120)] public int Age { get; set; } } |
Модель даних слугує для передавання даних між поданням (відображенням) і контролером. Модель UserViewModel містить набір властивостей, які будуть використовуватися для передачі даних про користувача між клієнтською стороною (веб-сторінкою) і серверною стороною (контролером).
Зазначено атрибут [Required], який також вимагає наявність значення, і атрибут [Range(10, 120)], який обмежує діапазон віку від 10 до 120.
Додавання контролера та подання
Основний акцент у розглянутому прикладі додатка зроблено на управлінні користувачі, тому що це створює чудову можливість для демонстрації різних засобів роботи з даними. Нам потрібен контролер, який отримуватиме НТТР-запити і транслюватиме їх в операції над об’єктами User, тож створіть папку Controllers, додайте до неї файл на ім’я HomeController.cs, з таким вмістом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
public class HomeController : Controller { private readonly IUser _users; public HomeController(IUser users) { _users = users; } [HttpGet] public IActionResult Index() { return View(_users.GetAllUsers()); } [HttpGet] public IActionResult CreateOrUpdate(string? userId) { if (userId != null) { var currentUser = _users.GetUser(userId); if (currentUser != null) { return View(new UserViewModel { Id = currentUser.Id, Name = currentUser.Name, Email = currentUser.Email, Age = currentUser.Age }); } } return View(); } [HttpPost] [AutoValidateAntiforgeryToken] public IActionResult CreateOrUpdate(UserViewModel uvm) { if (ModelState.IsValid) { var user = new User { Id = uvm.Id, Name = uvm.Name, Email = uvm.Email, Age = uvm.Age }; if (uvm.Id is null) { _users.AddUser(user); } else { _users.UpdateUser(user); } return RedirectToAction(nameof(Index)); } return View(uvm); } [HttpPost] [AutoValidateAntiforgeryToken] public IActionResult Delete(string userId) { _users.DeleteUser(userId); return RedirectToAction(nameof(Index)); } } |
Метод дії Index() передає колекцію об’єктів User зі сховища своєму поданню, яке відобразить користувачеві екранну таблицю з даними. Метод AddUser() зберігає нові об’єкти Product, які ґрунтуються на даних, отриманих у НТТР-запиті POST тощо.
Далі створіть папку Views/Home і помістіть у неї файл на ім’я Index.cshtml з таким вмістом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
@{ ViewData["Title"] = "All Users"; } @model IEnumerable<User> <div class="text-center"> <h1 class="display-4">All Users</h1> <div class="row g-4 py-5 row-cols-1"> <div> <a asp-controller="Home" asp-action="CreateOrUpdate" class="btn btn-primary">Create User</a> </div> </div> @if (Model.Count() == 0) { <div class="row"> <div class="col text-center p-2">No data</div> </div> } else { <div class="p-5 mb-4 bg-light rounded-3 ovx"> <table class="table table-hover"> <tr><th>Id</th><th>Name</th><th>Email</th><th>Age</th><th></th><th></th></tr> @foreach (User user in Model) { <tr> <td>@user.Id</td> <td>@user.Name</td> <td>@user.Email</td> <td>@user.Age</td> <td> <a class="btn btn-sm btn-primary" asp-controller="Home" asp-action="CreateOrUpdate" asp-route-userId="@user.Id">Update</a> </td> <td> <form asp-controller="Home" asp-action="Delete" asp-route-userId="@user.Id" method="post"> <button type="submit" class="btn btn-sm btn-danger">Delete</button> </form> </td> </tr> } </table> </div> } </div> |
Це подання відображає список користувачів, використовуючи дані моделі User, і надає можливості для оновлення та видалення записів про користувачів.
У папку Views/Home помістіть файл на ім’я CreateOrUpdate.cshtml з таким вмістом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
@using UsersCrud.ViewModels; @{ ViewData["Title"] = "Create / Update User"; } @model UserViewModel <div class="container px-4 py-5" id="hanging-icons"> <h2 class="pb-2 border-bottom">Create / Update User</h2> <a asp-controller="Home" asp-action="Index">Home</a> <div class="row g-4 py-5 row-cols-1"> <div class="p-5 mb-4 bg-light rounded-3 "> <form asp-controller="Home" asp-action="CreateOrUpdate" method="post"> <div asp-validation-summary="All" class="text-danger"></div> <input type="hidden" asp-for="Id" /> <div class="form-group"> <label asp-for="Name" class="control-label"></label> <input type="text" asp-for="Name" class="form-control" /> <span asp-validation-for="Name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Email" class="control-label"></label> <input type="text" asp-for="Email" class="form-control" /> <span asp-validation-for="Email" class="text-danger"></span> </div> <div class="form-group mb-3"> <label asp-for="Age" class="control-label"></label> <input type="text" asp-for="Age" class="form-control" /> <span asp-validation-for="Age" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Save" class="btn btn-primary" /> </div> </form> </div> </div> </div> |
Це подання надає інтерфейс для створення нового користувача або оновлення наявного. Поля форми пов’язані з властивостями моделі UserViewModel, що дає змогу передавати й обробляти дані між поданням і контролером.
Запустіть додаток і перевірте його роботу:
Приклад роботи з колекцією користувачів завершено.
Зберігання даних з Entity Framework Core
Тепер додамо інфраструктуру Entity Framework Core у проєкт, щоб побачити, як легко працювати з базою даних, водночас внісши мінімум змін у поточну структуру проєкту.
Для початку завантажимо бібліотеку Entity Framework Core Sql Server:
Або через Package Manager Console:
1 |
Install-Package Microsoft.EntityFrameworkCore.SqlServer |
Перейдемо до файлу appsettings.json і пропишемо конфігурацію підключення та логування (якщо файлу немає, створіть його в корені проєкту):
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=usersCrudDb;Trusted_Connection=True;" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Information" } }, "AllowedHosts": "*" } |
Рядки підключення визначаються у файлі appsettings.json, у коді вище наведено визначення рядка підключення для БД додатка GameStore. У проєкті застосовується версія LocalDB продукту SQL Server, яка спроєктована спеціально для розробників і не вимагає конфігурації або облікових даних.
Ви зобов’язані забезпечити, щоб рядок підключення був єдиним нерозривним рядком. Формат рядка підключення специфічний для кожного сервера баз даних.
Навіть у проєкті, що зберігає лише невеликий обсяг даних, важливо розуміти запити і команди SQL, які інфраструктура Entity Framework Core посилає серверу баз даних.
У корені проєкту визначимо папку Data, до якої додамо клас ApplicationContext, з таким вмістом:
1 2 3 4 5 6 7 8 |
public class ApplicationContext : DbContext { public ApplicationContext(DbContextOptions<ApplicationContext> context) : base(context) { } public DbSet<User> Users{ get; set; } } |
Тепер час оновити клас реалізації сховища, щоб звертатися до даних через клас контексту, визначений раніше. Змінимо код класу UserRepository, таким чином:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class UserRepository : IUser { private readonly ApplicationContext _context; public UserRepository(ApplicationContext context) { _context = context; } public void AddUser(User user) { user.Id = Guid.NewGuid().ToString(); _context.Users.Add(user); _context.SaveChanges(); } public void DeleteUser(string id) { _context.Users.Remove(new User { Id = id }); _context.SaveChanges(); } public IEnumerable<User> GetAllUsers() { return _context.Users.ToList(); } public User GetUser(string id) { return _context.Users.FirstOrDefault(e => e.ToString().Equals(id)); } public void UpdateUser(User user) { _context.Users.Update(user); _context.SaveChanges(); } } |
У додатку ASP.NET Core MVC, доступ до об’єктів контексту даних керується з використанням впровадження залежностей, і тому до класу UserRepository було додано конструктор, який приймає об’єкт ApplicationContext, який буде надано засобом впровадження залежностей під час виконання.
Властивість Users, визначену інтерфейсом сховища, можна реалізувати шляхом повернення властивості DbSet<User>, яка визначена в класі контексту. Аналогічно метод AddUser() реалізувати легко, тому що об’єкт DbSet<Product> визначає метод Add(), який приймає об’єкти User і зберігає їх на постійній основі.
Додайте в клас Program.cs оператори конфігурації, щоб повідомити інфраструктуру Entity Framework Core про те, яким чином використовувати рядок підключення, який має застосовувати постачальник БД, і як керувати класом контексту:
1 2 3 4 5 6 |
builder.Services.AddTransient<IUser, UserRepository>(); builder.Services.AddDbContext<ApplicationContext>(opts => { opts.UseSqlServer( builder.Configuration["ConnectionStrings:DefaultConnection"]); }); |
Не забудьте прибрати старий рядок або просто змінити його життєвий цикл:
1 |
builder.Services.AddSingleton<IUser, UserRepository>(); |
Інфраструктура Entity Framework Core керує базами даних через засіб, званий міграціями, які являють собою набори змін, що створюють або модифікують БД з метою її синхронізації з моделлю даних.
Для роботи з міграцією, необхідно завантажити таку бібліотеку –
Microsoft.EntityFrameworkCore.Tools
Або через Package Manager Console:
1 |
Install-Package Microsoft.EntityFrameworkCore.Tools |
Для створення міграції у вікні Package Manager Console введіть таку команду:
1 |
Add-Migration Init |
Init або Initial – загальноприйняте ім’я, яке використовується для міграції, що здійснює первинну підготовку БД.
Під час виконання команди, інфраструктура Entity Framework Сore інспектує проєкт, знаходить клас контексту і застосовує його для створення міграції. У результаті у вікні Solution Explorer з’явиться папка Migrations, що містить файли класів, оператори яких підготують БД.
Просто створити міграцію, яка являє собою всього лише набір інструкцій, недостатньо. Інструкції міграції повинні бути виконані, щоб створити БД, яка зможе зберігати дані програми. Для виконання інструкцій міграції, у вікні Package Manager Console виконайте команду:
1 |
Update-Database |
Інфраструктура Entity Fгamework Core підключиться до сервера баз даних, зазначеного в рядку підключення, і виконає оператори в міграції. Результатом буде БД, яку можна використовувати для зберігання об’єктів User.
Запустіть проєкт і перевірте його роботу. Проєкт був трохи спрощений, для того щоб початківцю-розробнику було легше розібратися, деякі речі я реалізував не так, як робив би в реальному проєкті.
Я сподіваюся, що вам сподобалося читати цю статтю, і вона виявилася легкою для розуміння. Будь ласка, дайте мені знати, якщо у вас є якісь коментарі або виправлення.
Так само вам може бути цікава попередня стаття – Приймання платежів через Liqpay Api в Asp.Net Core.
Ви хочете навчитися писати код мовою програмування C#?
Створювати різні інформаційні системи, що складаються з сайтів, мобільних клієнтів, десктопних додатків, телеграм-ботів тощо.
Переходьте до нас на сторінку Dijix і ознайомтеся з умовами навчання, ми спеціалізуємося тільки на індивідуальних заняттях, як для початківців, так і для просунутих програмістів. Ви можете взяти як одне заняття для опрацювання питання, що вас цікавить, так і кілька, для більш щільної роботи. Завдяки особистому кабінету, кожен студент підвищить якість свого навчання, у вашому розпорядженні:
- Доступ до пройденого матеріалу
- Тематичні статті
- Бібліотека книг
- Онлайн тестування
- Спілкування в закритих групах