Last active
June 3, 2026 19:12
-
-
Save sunmeat/bf5a3bff2e48cab0d886f84c4b93e814 to your computer and use it in GitHub Desktop.
code first: one-to-many example + migrations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // початкова версія: https://github.com/sunmeat/efcore_codefirst_ensurecreated | |
| // ApplicationDbContext.cs: | |
| using EFCoreCodeFirst.Models; | |
| using Microsoft.EntityFrameworkCore; | |
| using Microsoft.Extensions.Configuration; | |
| namespace EFCoreCodeFirst | |
| { | |
| // контекст бази даних | |
| public class AppDbContext : DbContext | |
| { | |
| public DbSet<User>? Users => Set<User>(); | |
| public DbSet<Order>? Orders => Set<Order>(); | |
| public DbSet<Product>? Products => Set<Product>(); | |
| public DbSet<Category>? Categories => Set<Category>(); | |
| public AppDbContext() | |
| { | |
| } | |
| protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | |
| { | |
| if (!optionsBuilder.IsConfigured) | |
| { | |
| var configuration = new ConfigurationBuilder() | |
| .SetBasePath(Directory.GetCurrentDirectory()) | |
| .AddJsonFile("appsettings.json") | |
| .Build(); | |
| optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection")); | |
| } | |
| } | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| // Models / Order.cs: | |
| namespace EFCoreCodeFirst.Models | |
| { | |
| public class Order | |
| { | |
| public int Id { get; set; } // первинний ключ | |
| public string ProductName { get; set; } = null!; | |
| public decimal Price { get; set; } | |
| public DateTime OrderDate { get; set; } = DateTime.UtcNow; | |
| // зовнішній ключ + навігаційна властивість (зв'язок з User) | |
| public int UserId { get; set; } // обов'язково! | |
| public User User { get; set; } = null!; // навігаційна властивість (опціонально, але дуже зручно) | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| // Models / Category.cs: | |
| namespace EFCoreCodeFirst.Models | |
| { | |
| public class Category | |
| { | |
| public int CategoryId { get; set; } // Primary Key | |
| public string? Name { get; set; } | |
| public ICollection<Product>? Products { get; set; } // 1 to many | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| // Models / Product.cs: | |
| namespace EFCoreCodeFirst.Models | |
| { | |
| public class Product | |
| { | |
| public int ProductId { get; set; } // Primary Key | |
| public string? Name { get; set; } | |
| public decimal Price { get; set; } | |
| public int CategoryId { get; set; } // Foreign Key | |
| public Category? Category { get; set; } // navigation property | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| // Program.cs: | |
| // без змін, додаткові методи - на ваш розсуд, про всяк випадок яка в мене була версія коду: | |
| using EFCoreCodeFirst.Models; | |
| using Microsoft.EntityFrameworkCore; | |
| namespace EFCoreCodeFirst | |
| { | |
| class Program | |
| { | |
| private static readonly string[] Headers = { "ID", "Ім'я", "Вік", "Створено" }; | |
| static async Task Main() | |
| { | |
| Console.Title = "Code First"; | |
| Console.OutputEncoding = System.Text.Encoding.UTF8; | |
| await using var db = new AppDbContext(); | |
| // !!! ці рядки вже не потрібні! | |
| // await db.Database.EnsureDeletedAsync(); // видаляє БД, якщо вона існувала | |
| // await db.Database.EnsureCreatedAsync(); // створює БД, якщо її не існує | |
| Console.WriteLine("Перевірка та застосування міграцій..."); | |
| await db.Database.MigrateAsync(); | |
| Console.WriteLine("Міграції застосовані (або вже були актуальні).\n"); | |
| Console.WriteLine("Демонстрація роботи з EF Core:\n"); | |
| // додавання одного запису | |
| await AddUserAsync(db, new User { Name = "Олександр", Age = 36 }); | |
| // додавання списку | |
| await AddUsersAsync(db, | |
| [ | |
| new User { Name = "Максим", Age = 24 }, | |
| new User { Name = "Ірина", Age = 22 }, | |
| new User { Name = "Софія", Age = 19 } | |
| ]); | |
| // поточний стан | |
| await PrintAllUsersAsync(db, "Початковий стан"); | |
| // оновлення | |
| await UpdateUserAgeAsync(db, 1, 26); | |
| await UpdateYoungUsersAgeAsync(db, 28); | |
| await PrintAllUsersAsync(db, "Після оновлення"); | |
| // видалення | |
| await DeleteUserAsync(db, 2); | |
| await PrintAllUsersAsync(db, "Після видалення одного користувача"); | |
| // await DeleteAllUsersAsync(db); | |
| // await PrintAllUsersAsync(db, "Після видалення всіх"); | |
| Console.WriteLine("\nНатисніть будь-яку клавішу для завершення..."); | |
| Console.ReadKey(true); | |
| } | |
| /////////////////////////////////////////////////////////////////// | |
| // методи роботи з даними (async) | |
| private static async Task AddUserAsync(AppDbContext db, User user) | |
| { | |
| db.Users.Add(user); | |
| await db.SaveChangesAsync(); | |
| Console.WriteLine($"Додано користувача: {user.Name} ({user.Age} років)"); | |
| } | |
| private static async Task AddUsersAsync(AppDbContext db, User[] users) | |
| { | |
| db.Users.AddRange(users); | |
| await db.SaveChangesAsync(); | |
| Console.WriteLine($"Додано {users.Length} користувачів"); | |
| } | |
| private static async Task UpdateUserAgeAsync(AppDbContext db, int id, int newAge) | |
| { | |
| var user = await db.Users.FindAsync(id); | |
| if (user is null) | |
| { | |
| Console.WriteLine($"Користувача з ID {id} не знайдено"); | |
| return; | |
| } | |
| user.Age = newAge; | |
| await db.SaveChangesAsync(); | |
| Console.WriteLine($"Оновлено вік для {user.Name} → {newAge}"); | |
| } | |
| private static async Task UpdateYoungUsersAgeAsync(AppDbContext db, int targetAge) | |
| { | |
| var youngUsers = await db.Users | |
| .Where(u => u.Age < targetAge) | |
| .ToListAsync(); | |
| if (youngUsers.Count == 0) return; | |
| foreach (var user in youngUsers) | |
| user.Age = targetAge; | |
| await db.SaveChangesAsync(); | |
| Console.WriteLine($"Оновлено вік ({targetAge} років) для {youngUsers.Count} молодих користувачів"); | |
| } | |
| private static async Task DeleteUserAsync(AppDbContext db, int id) | |
| { | |
| var user = await db.Users.FindAsync(id); | |
| if (user is null) return; | |
| db.Users.Remove(user); | |
| await db.SaveChangesAsync(); | |
| Console.WriteLine($"Видалено користувача: {user.Name}"); | |
| } | |
| private static async Task DeleteAllUsersAsync(AppDbContext db) | |
| { | |
| var count = await db.Users.CountAsync(); | |
| if (count == 0) return; | |
| db.Users.RemoveRange(db.Users); | |
| await db.SaveChangesAsync(); | |
| Console.WriteLine($"Видалено всіх користувачів ({count})"); | |
| } | |
| private static async Task PrintAllUsersAsync(AppDbContext db, string title) | |
| { | |
| var users = await db.Users | |
| .OrderBy(u => u.Id) | |
| .ToListAsync(); | |
| Console.WriteLine($"\n{title}"); | |
| Console.WriteLine(new string('-', 60)); | |
| if (users.Count == 0) | |
| { | |
| Console.WriteLine("Таблиця порожня"); | |
| return; | |
| } | |
| // красиве виведення таблицею | |
| Console.WriteLine($"{Headers[0],-4} | {Headers[1],-15} | {Headers[2],-5} | {Headers[3]}"); | |
| Console.WriteLine(new string('-', 60)); | |
| foreach (var u in users) | |
| { | |
| Console.WriteLine($"{u.Id,-4} | {u.Name,-15} | {u.Age,-5} | {u.CreatedAt:yyyy-MM-dd HH:mm}"); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment