From 09a0cb60c1c5f7801fd634d1cfe7482abcd5a150 Mon Sep 17 00:00:00 2001 From: tatyana-basargina Date: Wed, 24 Sep 2025 22:12:24 +0300 Subject: [PATCH 1/2] Homework EF: 1-6 --- .../Abstractions/Repositories/IRepository.cs | 6 + .../Domain/Administration/Employee.cs | 7 +- .../Domain/Administration/Role.cs | 4 +- .../Domain/PromoCodeManagement/Customer.cs | 4 +- .../PromoCodeManagement/CustomerPreference.cs | 12 + .../Domain/PromoCodeManagement/Preference.cs | 8 +- .../Domain/PromoCodeManagement/PromoCode.cs | 11 +- .../Data/FakeDataFactory.cs | 12 +- .../DataContext.cs | 131 +++++++++++ .../PromoCodeFactory.DataAccess.csproj | 14 ++ .../Repositories/EfRepository.cs | 90 ++++++++ .../Repositories/InMemoryRepository.cs | 15 ++ .../Controllers/CustomersController.cs | 213 ++++++++++++++++-- .../Controllers/EmployeesController.cs | 1 + .../Controllers/PreferenceController.cs | 43 ++++ .../Models/CustomerResponse.cs | 3 +- .../Models/PreferenceResponse.cs | 10 + .../src/PromoCodeFactory.WebHost/Startup.cs | 39 +++- .../PromoCodeFactory.WebHost/appsettings.json | 3 + 19 files changed, 587 insertions(+), 39 deletions(-) create mode 100644 Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/CustomerPreference.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/EfRepository.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PreferenceController.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.WebHost/Models/PreferenceResponse.cs diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Abstractions/Repositories/IRepository.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Abstractions/Repositories/IRepository.cs index a1eb21fe..bd6cd552 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Abstractions/Repositories/IRepository.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Abstractions/Repositories/IRepository.cs @@ -11,5 +11,11 @@ public interface IRepository Task> GetAllAsync(); Task GetByIdAsync(Guid id); + + Task AddAsync(T data); + + Task UpdateAsync(T data); + + Task DeleteAsync(Guid id); } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Employee.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Employee.cs index 28099d61..50b42913 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Employee.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Employee.cs @@ -1,4 +1,4 @@ -using PromoCodeFactory.Core.Domain; +using PromoCodeFactory.Core.Domain.PromoCodeManagement; using System; using System.Collections.Generic; @@ -14,8 +14,11 @@ public class Employee public string Email { get; set; } - public Role Role { get; set; } + public Guid RoleId { get; set; } + public virtual Role Role { get; set; } public int AppliedPromocodesCount { get; set; } + + public virtual List PromoCodes { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Role.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Role.cs index f0fadc21..ad219c8d 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Role.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/Administration/Role.cs @@ -1,5 +1,4 @@ -using PromoCodeFactory.Core.Domain; -using System; +using System.Collections.Generic; namespace PromoCodeFactory.Core.Domain.Administration { @@ -9,5 +8,6 @@ public class Role public string Name { get; set; } public string Description { get; set; } + public virtual List Employee { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Customer.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Customer.cs index 6f5c3593..92c3fab5 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Customer.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Customer.cs @@ -14,6 +14,8 @@ public class Customer public string Email { get; set; } - //TODO: Списки Preferences и Promocodes + // TODO: Списки Preferences и Promocodes + public virtual List Preferences { get; set; } + public virtual List Promocodes { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/CustomerPreference.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/CustomerPreference.cs new file mode 100644 index 00000000..1e42d8a4 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/CustomerPreference.cs @@ -0,0 +1,12 @@ +using System; + +namespace PromoCodeFactory.Core.Domain.PromoCodeManagement +{ + public class CustomerPreference + { + public Guid CustomerId { get; set; } + public virtual Customer Customer { get; set; } + public Guid PreferenceId { get; set; } + public virtual Preference Preference { get; set; } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Preference.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Preference.cs index 28e172a4..c8157d59 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Preference.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/Preference.cs @@ -1,8 +1,14 @@ -namespace PromoCodeFactory.Core.Domain.PromoCodeManagement +using System.Collections.Generic; + +namespace PromoCodeFactory.Core.Domain.PromoCodeManagement { public class Preference : BaseEntity { public string Name { get; set; } + + public virtual List PromoCodes { get; set; } + + public virtual List Customers { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs index 3305a41a..1439d731 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs @@ -1,6 +1,4 @@ using System; -using System.Runtime; -using PromoCodeFactory.Core.Domain; using PromoCodeFactory.Core.Domain.Administration; namespace PromoCodeFactory.Core.Domain.PromoCodeManagement @@ -18,8 +16,13 @@ public class PromoCode public string PartnerName { get; set; } - public Employee PartnerManager { get; set; } + public Guid? PartnerManagerId { get; set; } + public virtual Employee? PartnerManager { get; set; } - public Preference Preference { get; set; } + public Guid PreferenceId { get; set; } + public virtual Preference Preference { get; set; } + + public Guid? CustomerId { get; set; } + public virtual Customer? Customer { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Data/FakeDataFactory.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Data/FakeDataFactory.cs index aa665794..e4e46331 100644 --- a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Data/FakeDataFactory.cs +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Data/FakeDataFactory.cs @@ -16,7 +16,7 @@ public static class FakeDataFactory Email = "owner@somemail.ru", FirstName = "Иван", LastName = "Сергеев", - Role = Roles.FirstOrDefault(x => x.Name == "Admin"), + RoleId = Roles.FirstOrDefault(x => x.Name == "Admin").Id, AppliedPromocodesCount = 5 }, new Employee() @@ -25,7 +25,7 @@ public static class FakeDataFactory Email = "andreev@somemail.ru", FirstName = "Петр", LastName = "Андреев", - Role = Roles.FirstOrDefault(x => x.Name == "PartnerManager"), + RoleId = Roles.FirstOrDefault(x => x.Name == "PartnerManager").Id, AppliedPromocodesCount = 10 }, }; @@ -78,7 +78,13 @@ public static IEnumerable Customers Email = "ivan_sergeev@mail.ru", FirstName = "Иван", LastName = "Петров", - //TODO: Добавить предзаполненный список предпочтений + // TODO: Добавить предзаполненный список предпочтений + Preferences = new List() + { + Preferences.First(p => p.Name == "Театр"), + Preferences.First(p => p.Name == "Семья"), + Preferences.First(p => p.Name == "Дети"), + } } }; diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs new file mode 100644 index 00000000..164f07cb --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs @@ -0,0 +1,131 @@ +using Microsoft.EntityFrameworkCore; +using PromoCodeFactory.Core.Domain.Administration; +using PromoCodeFactory.Core.Domain.PromoCodeManagement; +using PromoCodeFactory.DataAccess.Data; +using System.Linq; + +namespace PromoCodeFactory.DataAccess +{ + public class DataContext : DbContext + { + // 4. Настроить маппинг классов Employee, Roles, Customer,Preference и PromoCode на базу данных через EF + public DbSet Employees { get; set; } + public DbSet Roles { get; set; } + public DbSet Preferences { get; set; } + public DbSet Customers { get; set; } + public DbSet PromoCodes { get; set; } + + public DataContext(DbContextOptions options) + : base(options) { } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + // 4. + // PromoCode имеет ссылку на Preference + modelBuilder.Entity() + .HasOne(p => p.Preference) + .WithMany(p => p.PromoCodes) + .HasForeignKey(p => p.PreferenceId); + + // Employee имеет ссылку на Role + modelBuilder.Entity() + .HasOne(e => e.Role) + .WithMany(r => r.Employee) + .HasForeignKey(e => e.RoleId); + + // Customer имеет набор Preference: Many-to-many через сущность CustomerPreference + modelBuilder.Entity() + .HasMany(c => c.Preferences) + .WithMany(p => p.Customers) + .UsingEntity( + j => j.HasOne(c => c.Preference) + .WithMany() + .HasForeignKey(cp => cp.PreferenceId), + j => j + .HasOne(c => c.Customer) + .WithMany() + .HasForeignKey(cp => cp.CustomerId), + j => + { + j.HasKey(cp => new { cp.CustomerId, cp.PreferenceId }); + j.ToTable("CustomerPreferences"); + } + ); + + // Связь Customer и Promocode реализовать через One-To-Many + modelBuilder.Entity() + .HasOne(p => p.Customer) + .WithMany(c => c.Promocodes) + .HasForeignKey(p => p.CustomerId) + .OnDelete(DeleteBehavior.Cascade); // 5. при удалении также нужно удалить ранее выданные промокоды клиента + + modelBuilder.Entity() + .HasOne(p => p.PartnerManager) + .WithMany(c => c.PromoCodes) + .HasForeignKey(p => p.PartnerManagerId) + .OnDelete(DeleteBehavior.SetNull); + + // Строковые поля должны иметь ограничения на MaxLength + modelBuilder.Entity(r => + { + r.Property(x => x.Name).HasMaxLength(255); + r.Property(x => x.Description).HasMaxLength(1000); + }); + + modelBuilder.Entity(e => + { + e.Property(x => x.FirstName).HasMaxLength(255); + e.Property(x => x.LastName).HasMaxLength(255); + e.Property(x => x.Email).HasMaxLength(255); + }); + + modelBuilder.Entity(p => + { + p.Property(x => x.Name).HasMaxLength(255); + }); + + modelBuilder.Entity(c => + { + c.Property(x => x.FirstName).HasMaxLength(255); + c.Property(x => x.LastName).HasMaxLength(255); + c.Property(x => x.Email).HasMaxLength(255); + }); + + modelBuilder.Entity(p => + { + p.Property(x => x.Code).HasMaxLength(20); + p.Property(x => x.ServiceInfo).HasMaxLength(1000); + p.Property(x => x.PartnerName).HasMaxLength(255); + }); + + // 3. База должна удаляться и создаваться каждый раз, заполняясь тестовыми данными из FakeDataFactory. + modelBuilder.Entity().HasData(FakeDataFactory.Roles); + modelBuilder.Entity().HasData(FakeDataFactory.Employees); + modelBuilder.Entity().HasData(FakeDataFactory.Preferences); + modelBuilder.Entity().HasData(FakeDataFactory.Customers + .Select(x => new Customer + { + Id = x.Id, + FirstName = x.FirstName, + LastName = x.LastName, + Email = x.Email, + Preferences = [], + })); + modelBuilder.Entity().HasData( + FakeDataFactory.Customers + .SelectMany(c => c.Preferences, (c, p) => new CustomerPreference + { + CustomerId = c.Id, + PreferenceId = p.Id + }) + ); + + base.OnModelCreating(modelBuilder); + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/PromoCodeFactory.DataAccess.csproj b/Homeworks/EF/src/PromoCodeFactory.DataAccess/PromoCodeFactory.DataAccess.csproj index 4b290698..d8dff9af 100644 --- a/Homeworks/EF/src/PromoCodeFactory.DataAccess/PromoCodeFactory.DataAccess.csproj +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/PromoCodeFactory.DataAccess.csproj @@ -4,6 +4,20 @@ net8.0 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/EfRepository.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/EfRepository.cs new file mode 100644 index 00000000..2dcfe56c --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/EfRepository.cs @@ -0,0 +1,90 @@ +using Microsoft.EntityFrameworkCore; +using PromoCodeFactory.Core.Abstractions.Repositories; +using PromoCodeFactory.Core.Domain; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace PromoCodeFactory.DataAccess.Repositories +{ + // 5. добавить новый Generic класс EfRepository + public class EfRepository : IRepository where T : BaseEntity + { + protected readonly DataContext _dataContext; + + public EfRepository(DataContext dataContext) + { + _dataContext = dataContext; + } + + /// + /// Получение списка + /// + /// Список + public async Task> GetAllAsync() + { + return await _dataContext.Set().ToListAsync(); + } + + /// + /// Получение одного элемента + /// + /// Id + /// + public async Task GetByIdAsync(Guid id) + { + return await _dataContext.Set().FirstAsync(t => t.Id == id); + } + + /// + /// Создание + /// + /// Новый элемент + /// Id + public async Task AddAsync(T data) + { + data.Id = Guid.NewGuid(); + await _dataContext.Set().AddAsync(data); + await _dataContext.SaveChangesAsync(); + return data.Id; + } + + /// + /// Редактирование + /// + /// Измененный элемент + /// Результат изменения: true, false + public async Task UpdateAsync(T data) + { + var dataUpdated = _dataContext.Set().Update(data); + + if (dataUpdated is null) + { + return false; + } + + await _dataContext.SaveChangesAsync(); + return true; + } + + /// + /// Удаление + /// + /// Id + /// Результат удаления: true, false + public async Task DeleteAsync(Guid id) + { + var data = await _dataContext.Set().FirstAsync(t => t.Id == id); + var dataRomoved = _dataContext.Set().Remove(data); + + if (dataRomoved is null) + { + return false; + } + + await _dataContext.SaveChangesAsync(true); + return true; + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/InMemoryRepository.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/InMemoryRepository.cs index dd099f5e..30774fa4 100644 --- a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/InMemoryRepository.cs +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Repositories/InMemoryRepository.cs @@ -27,5 +27,20 @@ public Task GetByIdAsync(Guid id) { return Task.FromResult(Data.FirstOrDefault(x => x.Id == id)); } + + public Task AddAsync(T data) + { + throw new NotImplementedException(); + } + + public Task UpdateAsync(T data) + { + throw new NotImplementedException(); + } + + public Task DeleteAsync(Guid id) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/CustomersController.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/CustomersController.cs index cf069a09..0180c521 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/CustomersController.cs +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/CustomersController.cs @@ -1,6 +1,10 @@ using Microsoft.AspNetCore.Mvc; +using PromoCodeFactory.Core.Abstractions.Repositories; +using PromoCodeFactory.Core.Domain.PromoCodeManagement; using PromoCodeFactory.WebHost.Models; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace PromoCodeFactory.WebHost.Controllers @@ -13,39 +17,218 @@ namespace PromoCodeFactory.WebHost.Controllers public class CustomersController : ControllerBase { + private readonly IRepository _customerRepository; + private readonly IRepository _preferenceRepository; + + public CustomersController(IRepository repository, IRepository preferenceRepository) + { + _customerRepository = repository; + _preferenceRepository = preferenceRepository; + } + + /// + /// Получить список клиетов + /// + /// Список клиентов [HttpGet] - public Task> GetCustomersAsync() + public async Task>> GetCustomersAsync() { - //TODO: Добавить получение списка клиентов - throw new NotImplementedException(); + // TODO: Добавить получение списка клиентов + IEnumerable customers; + try + { + customers = await _customerRepository.GetAllAsync(); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + return Ok(customers.Select(x => new CustomerShortResponse + { + Id = x.Id, + FirstName = x.FirstName, + LastName = x.LastName, + Email = x.Email + }).ToList()); } + /// + /// Получить данные клиента по Id + /// + /// Id клиента + /// Данные клиента [HttpGet("{id}")] - public Task> GetCustomerAsync(Guid id) + public async Task> GetCustomerAsync(Guid id) { - //TODO: Добавить получение клиента вместе с выданными ему промомкодами - throw new NotImplementedException(); + // TODO: Добавить получение клиента вместе с выданными ему промомкодами + Customer customer; + List promoCodes; + List preferences; + try + { + customer = await _customerRepository.GetByIdAsync(id); + promoCodes = customer.Promocodes?.Select(p => new PromoCodeShortResponse + { + Id = p.Id, + Code = p.Code, + ServiceInfo = p.ServiceInfo, + BeginDate = p.BeginDate.ToString(), + EndDate = p.EndDate.ToString(), + PartnerName = p.PartnerName + }).ToList(); + + // 5. CustomerResponse также должен возвращать список предпочтений клиента с той же моделью PrefernceResponse + preferences = customer.Preferences?.Select(p => new PreferenceResponse + { + Id = p.Id, + Name = p.Name, + }).ToList(); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + return Ok(new CustomerResponse + { + Id = customer.Id, + FirstName = customer.FirstName, + LastName = customer.LastName, + Email = customer.Email, + Preferences = preferences, + PromoCodes = promoCodes + }); } + /// + /// Добавить клиента + /// + /// Данные клиента + /// Результат добавления: Id [HttpPost] - public Task CreateCustomerAsync(CreateOrEditCustomerRequest request) + public async Task> CreateCustomerAsync([FromBody] CreateOrEditCustomerRequest request) { - //TODO: Добавить создание нового клиента вместе с его предпочтениями - throw new NotImplementedException(); + // TODO: Добавить создание нового клиента вместе с его предпочтениями + Customer customer = new() + { + FirstName = request.FirstName, + LastName = request.LastName, + Email = request.Email, + Preferences = [] + }; + + foreach (var preferenceId in request?.PreferenceIds.Distinct()) + { + Preference preference; + try + { + preference = await _preferenceRepository.GetByIdAsync(preferenceId); + } + catch (Exception ex) + { + return NotFound(ex.Message); + } + + customer.Preferences.Add(preference); + } + + Guid newId = Guid.Empty; + try + { + newId = await _customerRepository.AddAsync(customer); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + return Ok(newId); } + /// + /// Обновить данные клиента по Id + /// + /// Id клиента + /// Новые данные клиента + /// Результат обновления: true, false [HttpPut("{id}")] - public Task EditCustomersAsync(Guid id, CreateOrEditCustomerRequest request) + public async Task> EditCustomersAsync(Guid id, [FromBody] CreateOrEditCustomerRequest request) { - //TODO: Обновить данные клиента вместе с его предпочтениями - throw new NotImplementedException(); + // TODO: Обновить данные клиента вместе с его предпочтениями + Customer customer; + try + { + customer = await _customerRepository.GetByIdAsync(id); + } + catch (Exception ex) + { + return NotFound(ex.Message); + } + + customer.FirstName = request.FirstName; + customer.LastName = request.LastName; + customer.Email = request.Email; + + if (customer.Preferences is null) + { + customer.Preferences = []; + } + else + { + customer.Preferences.Clear(); + } + + if (request.PreferenceIds.Count != 0) + { + foreach (var preferenceId in request?.PreferenceIds.Distinct()) + { + Preference preference; + try + { + preference = await _preferenceRepository.GetByIdAsync(preferenceId); + } + catch (Exception ex) + { + return NotFound(ex.Message); + } + + customer.Preferences.Add(preference); + } + } + + bool result; + try + { + result = await _customerRepository.UpdateAsync(customer); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + return Ok(result); } + /// + /// Удалить клиента по Id + /// + /// Id клиента + /// Результат удаления: true, false [HttpDelete] - public Task DeleteCustomer(Guid id) + public async Task> DeleteCustomer(Guid id) { - //TODO: Удаление клиента вместе с выданными ему промокодами - throw new NotImplementedException(); + // TODO: Удаление клиента вместе с выданными ему промокодами + bool result; + try + { + result = await _customerRepository.DeleteAsync(id); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + return Ok(result); } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/EmployeesController.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/EmployeesController.cs index 2dd31dd2..d79e239f 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/EmployeesController.cs +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/EmployeesController.cs @@ -62,6 +62,7 @@ public async Task> GetEmployeeByIdAsync(Guid id) Email = employee.Email, Role = new RoleItemResponse() { + Id = employee.Role.Id, Name = employee.Role.Name, Description = employee.Role.Description }, diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PreferenceController.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PreferenceController.cs new file mode 100644 index 00000000..5cb451de --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PreferenceController.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Mvc; +using PromoCodeFactory.Core.Abstractions.Repositories; +using PromoCodeFactory.Core.Domain.PromoCodeManagement; +using PromoCodeFactory.WebHost.Models; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace PromoCodeFactory.WebHost.Controllers +{ + /// + /// Предпочтения + /// + [ApiController] + [Route("api/v1/[controller]")] + public class PreferenceController : Controller + { + private readonly IRepository _preferenceRepository; + public PreferenceController(IRepository preferenceRepository) + { + _preferenceRepository = preferenceRepository; + } + + /// + /// Получить все предпочтения + /// + /// Список предпочтений + [HttpGet] + public async Task> GetRolesAsync() + { + var preference = await _preferenceRepository.GetAllAsync(); + + var preferencesModelList = preference.Select(x => + new PreferenceResponse() + { + Id = x.Id, + Name = x.Name + }).ToList(); + + return preferencesModelList; + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/CustomerResponse.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/CustomerResponse.cs index 97ea3e6b..33983d8c 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/CustomerResponse.cs +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/CustomerResponse.cs @@ -9,7 +9,8 @@ public class CustomerResponse public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } - //TODO: Добавить список предпочтений + // TODO: Добавить список предпочтений + public List Preferences { get; set; } public List PromoCodes { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/PreferenceResponse.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/PreferenceResponse.cs new file mode 100644 index 00000000..2d8814b0 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Models/PreferenceResponse.cs @@ -0,0 +1,10 @@ +using System; + +namespace PromoCodeFactory.WebHost.Models +{ + public class PreferenceResponse + { + public Guid Id { get; set; } + public string Name { get; set; } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs index 73a898fc..eb69134e 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs @@ -1,10 +1,13 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using PromoCodeFactory.Core.Abstractions.Repositories; using PromoCodeFactory.Core.Domain.Administration; using PromoCodeFactory.Core.Domain.PromoCodeManagement; +using PromoCodeFactory.DataAccess; using PromoCodeFactory.DataAccess.Data; using PromoCodeFactory.DataAccess.Repositories; @@ -12,19 +15,32 @@ namespace PromoCodeFactory.WebHost { public class Startup { + public IConfiguration Configuration { get; } + + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddControllers(); - services.AddScoped(typeof(IRepository), (x) => - new InMemoryRepository(FakeDataFactory.Employees)); - services.AddScoped(typeof(IRepository), (x) => - new InMemoryRepository(FakeDataFactory.Roles)); - services.AddScoped(typeof(IRepository), (x) => - new InMemoryRepository(FakeDataFactory.Preferences)); - services.AddScoped(typeof(IRepository), (x) => - new InMemoryRepository(FakeDataFactory.Customers)); + + // 1. сделать реализацию IRepository в виде EfRepository + services.AddScoped, EfRepository>(); + services.AddScoped, EfRepository>(); + services.AddScoped, EfRepository>(); + services.AddScoped, EfRepository>(); + services.AddScoped, EfRepository>(); + + services.AddDbContext(options => + { + // 2. Добавить SQLite в качестве БД + options.UseSqlite(Configuration.GetConnectionString("SqliteConnection")); + options.UseLazyLoadingProxies(); + }); services.AddOpenApiDocument(options => { @@ -34,11 +50,14 @@ public void ConfigureServices(IServiceCollection services) } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dbContext) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); + // 3. База должна удаляться и создаваться каждый раз + dbContext.Database.EnsureDeleted(); + dbContext.Database.EnsureCreated(); } else { diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/appsettings.json b/Homeworks/EF/src/PromoCodeFactory.WebHost/appsettings.json index d9d9a9bf..1a08aeee 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/appsettings.json +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/appsettings.json @@ -6,5 +6,8 @@ "Microsoft.Hosting.Lifetime": "Information" } }, + "ConnectionStrings": { + "SqliteConnection": "Data Source=app.db" + }, "AllowedHosts": "*" } From bd2cb2e0108e961e1af2a12334315ed27108c2b0 Mon Sep 17 00:00:00 2001 From: tatyana-basargina Date: Thu, 25 Sep 2025 01:40:19 +0300 Subject: [PATCH 2/2] Homework EF: 7-8 --- .../Domain/PromoCodeManagement/PromoCode.cs | 6 +- .../DataContext.cs | 28 +- .../20250924204144_InitialCreate.Designer.cs | 328 +++++++++++++++++ .../20250924204144_InitialCreate.cs | 229 ++++++++++++ ...321_AddCustomerPromoCodesTable.Designer.cs | 341 ++++++++++++++++++ ...250924205321_AddCustomerPromoCodesTable.cs | 82 +++++ ..._UpdateCustomerPromoCodesTable.Designer.cs | 341 ++++++++++++++++++ ...924215904_UpdateCustomerPromoCodesTable.cs | 66 ++++ .../Migrations/DataContextModelSnapshot.cs | 338 +++++++++++++++++ .../Controllers/PromocodesController.cs | 67 +++- .../PromoCodeFactory.WebHost.csproj | 8 + .../src/PromoCodeFactory.WebHost/Startup.cs | 12 +- 12 files changed, 1827 insertions(+), 19 deletions(-) create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.Designer.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.Designer.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.Designer.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.cs create mode 100644 Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/DataContextModelSnapshot.cs diff --git a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs index 1439d731..8cbc1f3c 100644 --- a/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs +++ b/Homeworks/EF/src/PromoCodeFactory.Core/Domain/PromoCodeManagement/PromoCode.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using PromoCodeFactory.Core.Domain.Administration; namespace PromoCodeFactory.Core.Domain.PromoCodeManagement @@ -22,7 +23,8 @@ public class PromoCode public Guid PreferenceId { get; set; } public virtual Preference Preference { get; set; } - public Guid? CustomerId { get; set; } - public virtual Customer? Customer { get; set; } + //public Guid? CustomerId { get; set; } + //public virtual Customer? Customer { get; set; } + public virtual List Customers { get; set; } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs index 164f07cb..c8235a8a 100644 --- a/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/DataContext.cs @@ -1,7 +1,10 @@ -using Microsoft.EntityFrameworkCore; +using Castle.Core.Resource; +using Microsoft.EntityFrameworkCore; using PromoCodeFactory.Core.Domain.Administration; using PromoCodeFactory.Core.Domain.PromoCodeManagement; using PromoCodeFactory.DataAccess.Data; +using System; +using System.Collections.Generic; using System.Linq; namespace PromoCodeFactory.DataAccess @@ -58,11 +61,24 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) ); // Связь Customer и Promocode реализовать через One-To-Many - modelBuilder.Entity() - .HasOne(p => p.Customer) - .WithMany(c => c.Promocodes) - .HasForeignKey(p => p.CustomerId) - .OnDelete(DeleteBehavior.Cascade); // 5. при удалении также нужно удалить ранее выданные промокоды клиента + //modelBuilder.Entity() + // .HasOne(p => p.Customer) + // .WithMany(c => c.Promocodes) + // .HasForeignKey(p => p.CustomerId) + // .OnDelete(DeleteBehavior.Cascade); // 5. при удалении также нужно удалить ранее выданные промокоды клиента + + + // 7.Связь Customer и Promocode реализовать через Many-To-Many + // при удалении также нужно удалить ранее выданные промокоды клиента + modelBuilder.Entity() + .HasMany(c => c.Promocodes) + .WithMany(p => p.Customers) + .UsingEntity>( + "CustomerPromoCodes", + j => j.HasOne().WithMany().HasForeignKey("PromoCodeId").OnDelete(DeleteBehavior.Cascade), + j => j.HasOne().WithMany().HasForeignKey("CustomerId").OnDelete(DeleteBehavior.Cascade), + j => j.HasKey("CustomerId", "PromoCodeId") + ); modelBuilder.Entity() .HasOne(p => p.PartnerManager) diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.Designer.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.Designer.cs new file mode 100644 index 00000000..aaf18787 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.Designer.cs @@ -0,0 +1,328 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PromoCodeFactory.DataAccess; + +#nullable disable + +namespace PromoCodeFactory.DataAccess.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250924204144_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AppliedPromocodesCount") + .HasColumnType("INTEGER"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("Employees"); + + b.HasData( + new + { + Id = new Guid("451533d5-d8d5-4a11-9c7b-eb9f14e1a32f"), + AppliedPromocodesCount = 5, + Email = "owner@somemail.ru", + FirstName = "Иван", + LastName = "Сергеев", + RoleId = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02") + }, + new + { + Id = new Guid("f766e2bf-340a-46ea-bff3-f1700b435895"), + AppliedPromocodesCount = 10, + Email = "andreev@somemail.ru", + FirstName = "Петр", + LastName = "Андреев", + RoleId = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + + b.HasData( + new + { + Id = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02"), + Description = "Администратор", + Name = "Admin" + }, + new + { + Id = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665"), + Description = "Партнерский менеджер", + Name = "PartnerManager" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + Email = "ivan_sergeev@mail.ru", + FirstName = "Иван", + LastName = "Петров" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PreferenceId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("CustomerPreferences", (string)null); + + b.HasData( + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Preferences"); + + b.HasData( + new + { + Id = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c"), + Name = "Театр" + }, + new + { + Id = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd"), + Name = "Семья" + }, + new + { + Id = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84"), + Name = "Дети" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("BeginDate") + .HasColumnType("TEXT"); + + b.Property("Code") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("PartnerManagerId") + .HasColumnType("TEXT"); + + b.Property("PartnerName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.Property("ServiceInfo") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.HasIndex("PartnerManagerId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("PromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Role", "Role") + .WithMany("Employee") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany() + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", "Customer") + .WithMany("Promocodes") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Employee", "PartnerManager") + .WithMany("PromoCodes") + .HasForeignKey("PartnerManagerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany("PromoCodes") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("PartnerManager"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Navigation("PromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Navigation("Employee"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", b => + { + b.Navigation("Promocodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Navigation("PromoCodes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.cs new file mode 100644 index 00000000..62812b2d --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924204144_InitialCreate.cs @@ -0,0 +1,229 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace PromoCodeFactory.DataAccess.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Customers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + FirstName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + LastName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 255, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Customers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Preferences", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 255, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Preferences", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Roles", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 255, nullable: true), + Description = table.Column(type: "TEXT", maxLength: 1000, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Roles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CustomerPreferences", + columns: table => new + { + CustomerId = table.Column(type: "TEXT", nullable: false), + PreferenceId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomerPreferences", x => new { x.CustomerId, x.PreferenceId }); + table.ForeignKey( + name: "FK_CustomerPreferences_Customers_CustomerId", + column: x => x.CustomerId, + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CustomerPreferences_Preferences_PreferenceId", + column: x => x.PreferenceId, + principalTable: "Preferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Employees", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + FirstName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + LastName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 255, nullable: true), + RoleId = table.Column(type: "TEXT", nullable: false), + AppliedPromocodesCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Employees", x => x.Id); + table.ForeignKey( + name: "FK_Employees_Roles_RoleId", + column: x => x.RoleId, + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PromoCodes", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Code = table.Column(type: "TEXT", maxLength: 20, nullable: true), + ServiceInfo = table.Column(type: "TEXT", maxLength: 1000, nullable: true), + BeginDate = table.Column(type: "TEXT", nullable: false), + EndDate = table.Column(type: "TEXT", nullable: false), + PartnerName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + PartnerManagerId = table.Column(type: "TEXT", nullable: true), + PreferenceId = table.Column(type: "TEXT", nullable: false), + CustomerId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PromoCodes", x => x.Id); + table.ForeignKey( + name: "FK_PromoCodes_Customers_CustomerId", + column: x => x.CustomerId, + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PromoCodes_Employees_PartnerManagerId", + column: x => x.PartnerManagerId, + principalTable: "Employees", + principalColumn: "Id", + onDelete: ReferentialAction.SetNull); + table.ForeignKey( + name: "FK_PromoCodes_Preferences_PreferenceId", + column: x => x.PreferenceId, + principalTable: "Preferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + table: "Customers", + columns: new[] { "Id", "Email", "FirstName", "LastName" }, + values: new object[] { new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), "ivan_sergeev@mail.ru", "Иван", "Петров" }); + + migrationBuilder.InsertData( + table: "Preferences", + columns: new[] { "Id", "Name" }, + values: new object[,] + { + { new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84"), "Дети" }, + { new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd"), "Семья" }, + { new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c"), "Театр" } + }); + + migrationBuilder.InsertData( + table: "Roles", + columns: new[] { "Id", "Description", "Name" }, + values: new object[,] + { + { new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02"), "Администратор", "Admin" }, + { new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665"), "Партнерский менеджер", "PartnerManager" } + }); + + migrationBuilder.InsertData( + table: "CustomerPreferences", + columns: new[] { "CustomerId", "PreferenceId" }, + values: new object[,] + { + { new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84") }, + { new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd") }, + { new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c") } + }); + + migrationBuilder.InsertData( + table: "Employees", + columns: new[] { "Id", "AppliedPromocodesCount", "Email", "FirstName", "LastName", "RoleId" }, + values: new object[,] + { + { new Guid("451533d5-d8d5-4a11-9c7b-eb9f14e1a32f"), 5, "owner@somemail.ru", "Иван", "Сергеев", new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02") }, + { new Guid("f766e2bf-340a-46ea-bff3-f1700b435895"), 10, "andreev@somemail.ru", "Петр", "Андреев", new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665") } + }); + + migrationBuilder.CreateIndex( + name: "IX_CustomerPreferences_PreferenceId", + table: "CustomerPreferences", + column: "PreferenceId"); + + migrationBuilder.CreateIndex( + name: "IX_Employees_RoleId", + table: "Employees", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_PromoCodes_CustomerId", + table: "PromoCodes", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_PromoCodes_PartnerManagerId", + table: "PromoCodes", + column: "PartnerManagerId"); + + migrationBuilder.CreateIndex( + name: "IX_PromoCodes_PreferenceId", + table: "PromoCodes", + column: "PreferenceId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CustomerPreferences"); + + migrationBuilder.DropTable( + name: "PromoCodes"); + + migrationBuilder.DropTable( + name: "Customers"); + + migrationBuilder.DropTable( + name: "Employees"); + + migrationBuilder.DropTable( + name: "Preferences"); + + migrationBuilder.DropTable( + name: "Roles"); + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.Designer.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.Designer.cs new file mode 100644 index 00000000..102c6130 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.Designer.cs @@ -0,0 +1,341 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PromoCodeFactory.DataAccess; + +#nullable disable + +namespace PromoCodeFactory.DataAccess.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250924205321_AddCustomerPromoCodesTable")] + partial class AddCustomerPromoCodesTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("CustomerPromoCodes", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PromoCodeId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PromoCodeId"); + + b.HasIndex("PromoCodeId"); + + b.ToTable("CustomerPromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AppliedPromocodesCount") + .HasColumnType("INTEGER"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("Employees"); + + b.HasData( + new + { + Id = new Guid("451533d5-d8d5-4a11-9c7b-eb9f14e1a32f"), + AppliedPromocodesCount = 5, + Email = "owner@somemail.ru", + FirstName = "Иван", + LastName = "Сергеев", + RoleId = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02") + }, + new + { + Id = new Guid("f766e2bf-340a-46ea-bff3-f1700b435895"), + AppliedPromocodesCount = 10, + Email = "andreev@somemail.ru", + FirstName = "Петр", + LastName = "Андреев", + RoleId = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + + b.HasData( + new + { + Id = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02"), + Description = "Администратор", + Name = "Admin" + }, + new + { + Id = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665"), + Description = "Партнерский менеджер", + Name = "PartnerManager" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + Email = "ivan_sergeev@mail.ru", + FirstName = "Иван", + LastName = "Петров" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PreferenceId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("CustomerPreferences", (string)null); + + b.HasData( + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Preferences"); + + b.HasData( + new + { + Id = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c"), + Name = "Театр" + }, + new + { + Id = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd"), + Name = "Семья" + }, + new + { + Id = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84"), + Name = "Дети" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("BeginDate") + .HasColumnType("TEXT"); + + b.Property("Code") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("PartnerManagerId") + .HasColumnType("TEXT"); + + b.Property("PartnerName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.Property("ServiceInfo") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PartnerManagerId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("PromoCodes"); + }); + + modelBuilder.Entity("CustomerPromoCodes", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", null) + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", null) + .WithMany() + .HasForeignKey("PromoCodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Role", "Role") + .WithMany("Employee") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany() + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Employee", "PartnerManager") + .WithMany("PromoCodes") + .HasForeignKey("PartnerManagerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany("PromoCodes") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PartnerManager"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Navigation("PromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Navigation("Employee"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Navigation("PromoCodes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.cs new file mode 100644 index 00000000..791346a9 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924205321_AddCustomerPromoCodesTable.cs @@ -0,0 +1,82 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PromoCodeFactory.DataAccess.Migrations +{ + /// + public partial class AddCustomerPromoCodesTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_PromoCodes_Customers_CustomerId", + table: "PromoCodes"); + + migrationBuilder.DropIndex( + name: "IX_PromoCodes_CustomerId", + table: "PromoCodes"); + + migrationBuilder.DropColumn( + name: "CustomerId", + table: "PromoCodes"); + + migrationBuilder.CreateTable( + name: "CustomerPromoCodes", + columns: table => new + { + CustomerId = table.Column(type: "TEXT", nullable: false), + PromoCodeId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomerPromoCodes", x => new { x.CustomerId, x.PromoCodeId }); + table.ForeignKey( + name: "FK_CustomerPromoCodes_Customers_PromoCodeId", + column: x => x.PromoCodeId, + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CustomerPromoCodes_PromoCodes_CustomerId", + column: x => x.CustomerId, + principalTable: "PromoCodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_CustomerPromoCodes_PromoCodeId", + table: "CustomerPromoCodes", + column: "PromoCodeId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CustomerPromoCodes"); + + migrationBuilder.AddColumn( + name: "CustomerId", + table: "PromoCodes", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_PromoCodes_CustomerId", + table: "PromoCodes", + column: "CustomerId"); + + migrationBuilder.AddForeignKey( + name: "FK_PromoCodes_Customers_CustomerId", + table: "PromoCodes", + column: "CustomerId", + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.Designer.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.Designer.cs new file mode 100644 index 00000000..80414083 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.Designer.cs @@ -0,0 +1,341 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PromoCodeFactory.DataAccess; + +#nullable disable + +namespace PromoCodeFactory.DataAccess.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250924215904_UpdateCustomerPromoCodesTable")] + partial class UpdateCustomerPromoCodesTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("CustomerPromoCodes", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PromoCodeId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PromoCodeId"); + + b.HasIndex("PromoCodeId"); + + b.ToTable("CustomerPromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AppliedPromocodesCount") + .HasColumnType("INTEGER"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("Employees"); + + b.HasData( + new + { + Id = new Guid("451533d5-d8d5-4a11-9c7b-eb9f14e1a32f"), + AppliedPromocodesCount = 5, + Email = "owner@somemail.ru", + FirstName = "Иван", + LastName = "Сергеев", + RoleId = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02") + }, + new + { + Id = new Guid("f766e2bf-340a-46ea-bff3-f1700b435895"), + AppliedPromocodesCount = 10, + Email = "andreev@somemail.ru", + FirstName = "Петр", + LastName = "Андреев", + RoleId = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + + b.HasData( + new + { + Id = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02"), + Description = "Администратор", + Name = "Admin" + }, + new + { + Id = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665"), + Description = "Партнерский менеджер", + Name = "PartnerManager" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + Email = "ivan_sergeev@mail.ru", + FirstName = "Иван", + LastName = "Петров" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PreferenceId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("CustomerPreferences", (string)null); + + b.HasData( + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Preferences"); + + b.HasData( + new + { + Id = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c"), + Name = "Театр" + }, + new + { + Id = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd"), + Name = "Семья" + }, + new + { + Id = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84"), + Name = "Дети" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("BeginDate") + .HasColumnType("TEXT"); + + b.Property("Code") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("PartnerManagerId") + .HasColumnType("TEXT"); + + b.Property("PartnerName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.Property("ServiceInfo") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PartnerManagerId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("PromoCodes"); + }); + + modelBuilder.Entity("CustomerPromoCodes", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", null) + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", null) + .WithMany() + .HasForeignKey("PromoCodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Role", "Role") + .WithMany("Employee") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany() + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Employee", "PartnerManager") + .WithMany("PromoCodes") + .HasForeignKey("PartnerManagerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany("PromoCodes") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PartnerManager"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Navigation("PromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Navigation("Employee"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Navigation("PromoCodes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.cs new file mode 100644 index 00000000..8ffca5d0 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/20250924215904_UpdateCustomerPromoCodesTable.cs @@ -0,0 +1,66 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PromoCodeFactory.DataAccess.Migrations +{ + /// + public partial class UpdateCustomerPromoCodesTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_CustomerPromoCodes_Customers_PromoCodeId", + table: "CustomerPromoCodes"); + + migrationBuilder.DropForeignKey( + name: "FK_CustomerPromoCodes_PromoCodes_CustomerId", + table: "CustomerPromoCodes"); + + migrationBuilder.AddForeignKey( + name: "FK_CustomerPromoCodes_Customers_CustomerId", + table: "CustomerPromoCodes", + column: "CustomerId", + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_CustomerPromoCodes_PromoCodes_PromoCodeId", + table: "CustomerPromoCodes", + column: "PromoCodeId", + principalTable: "PromoCodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_CustomerPromoCodes_Customers_CustomerId", + table: "CustomerPromoCodes"); + + migrationBuilder.DropForeignKey( + name: "FK_CustomerPromoCodes_PromoCodes_PromoCodeId", + table: "CustomerPromoCodes"); + + migrationBuilder.AddForeignKey( + name: "FK_CustomerPromoCodes_Customers_PromoCodeId", + table: "CustomerPromoCodes", + column: "PromoCodeId", + principalTable: "Customers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_CustomerPromoCodes_PromoCodes_CustomerId", + table: "CustomerPromoCodes", + column: "CustomerId", + principalTable: "PromoCodes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/DataContextModelSnapshot.cs b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 00000000..d0f7d4e9 --- /dev/null +++ b/Homeworks/EF/src/PromoCodeFactory.DataAccess/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,338 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PromoCodeFactory.DataAccess; + +#nullable disable + +namespace PromoCodeFactory.DataAccess.Migrations +{ + [DbContext(typeof(DataContext))] + partial class DataContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("CustomerPromoCodes", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PromoCodeId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PromoCodeId"); + + b.HasIndex("PromoCodeId"); + + b.ToTable("CustomerPromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AppliedPromocodesCount") + .HasColumnType("INTEGER"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("Employees"); + + b.HasData( + new + { + Id = new Guid("451533d5-d8d5-4a11-9c7b-eb9f14e1a32f"), + AppliedPromocodesCount = 5, + Email = "owner@somemail.ru", + FirstName = "Иван", + LastName = "Сергеев", + RoleId = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02") + }, + new + { + Id = new Guid("f766e2bf-340a-46ea-bff3-f1700b435895"), + AppliedPromocodesCount = 10, + Email = "andreev@somemail.ru", + FirstName = "Петр", + LastName = "Андреев", + RoleId = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + + b.HasData( + new + { + Id = new Guid("53729686-a368-4eeb-8bfa-cc69b6050d02"), + Description = "Администратор", + Name = "Admin" + }, + new + { + Id = new Guid("b0ae7aac-5493-45cd-ad16-87426a5e7665"), + Description = "Партнерский менеджер", + Name = "PartnerManager" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Customers"); + + b.HasData( + new + { + Id = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + Email = "ivan_sergeev@mail.ru", + FirstName = "Иван", + LastName = "Петров" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.Property("CustomerId") + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.HasKey("CustomerId", "PreferenceId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("CustomerPreferences", (string)null); + + b.HasData( + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd") + }, + new + { + CustomerId = new Guid("a6c8c6b1-4349-45b0-ab31-244740aaf0f0"), + PreferenceId = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84") + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Preferences"); + + b.HasData( + new + { + Id = new Guid("ef7f299f-92d7-459f-896e-078ed53ef99c"), + Name = "Театр" + }, + new + { + Id = new Guid("c4bda62e-fc74-4256-a956-4760b3858cbd"), + Name = "Семья" + }, + new + { + Id = new Guid("76324c47-68d2-472d-abb8-33cfa8cc0c84"), + Name = "Дети" + }); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("BeginDate") + .HasColumnType("TEXT"); + + b.Property("Code") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("PartnerManagerId") + .HasColumnType("TEXT"); + + b.Property("PartnerName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PreferenceId") + .HasColumnType("TEXT"); + + b.Property("ServiceInfo") + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PartnerManagerId"); + + b.HasIndex("PreferenceId"); + + b.ToTable("PromoCodes"); + }); + + modelBuilder.Entity("CustomerPromoCodes", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", null) + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", null) + .WithMany() + .HasForeignKey("PromoCodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Role", "Role") + .WithMany("Employee") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.CustomerPreference", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany() + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.PromoCode", b => + { + b.HasOne("PromoCodeFactory.Core.Domain.Administration.Employee", "PartnerManager") + .WithMany("PromoCodes") + .HasForeignKey("PartnerManagerId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", "Preference") + .WithMany("PromoCodes") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PartnerManager"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Employee", b => + { + b.Navigation("PromoCodes"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.Administration.Role", b => + { + b.Navigation("Employee"); + }); + + modelBuilder.Entity("PromoCodeFactory.Core.Domain.PromoCodeManagement.Preference", b => + { + b.Navigation("PromoCodes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PromocodesController.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PromocodesController.cs index 5b96c327..a08b6c56 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PromocodesController.cs +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Controllers/PromocodesController.cs @@ -1,8 +1,11 @@ -using System; +using Microsoft.AspNetCore.Mvc; +using PromoCodeFactory.Core.Abstractions.Repositories; +using PromoCodeFactory.Core.Domain.PromoCodeManagement; +using PromoCodeFactory.WebHost.Models; +using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using PromoCodeFactory.WebHost.Models; namespace PromoCodeFactory.WebHost.Controllers { @@ -14,15 +17,37 @@ namespace PromoCodeFactory.WebHost.Controllers public class PromocodesController : ControllerBase { + protected readonly IRepository _promoCodesRepository; + protected readonly IRepository _preferenceRepository; + + public PromocodesController(IRepository promoCodesRepository, IRepository preferenceRepository) + { + _promoCodesRepository = promoCodesRepository; + _preferenceRepository = preferenceRepository; + } + /// /// Получить все промокоды /// /// [HttpGet] - public Task>> GetPromocodesAsync() + public async Task>> GetPromocodesAsync() { - //TODO: Получить все промокоды - throw new NotImplementedException(); + // TODO: Получить все промокоды + var promoCodes = await _promoCodesRepository.GetAllAsync(); + + var promoCodesModelList = promoCodes.Select(x => + new PromoCodeShortResponse() + { + Id = x.Id, + Code = x.Code, + ServiceInfo = x.ServiceInfo.ToString(), + BeginDate = x.BeginDate.ToString(), + EndDate = x.EndDate.ToString(), + PartnerName = x.PartnerName + }).ToList(); + + return Ok(promoCodesModelList); } /// @@ -30,10 +55,34 @@ public Task>> GetPromocodesAsync() /// /// [HttpPost] - public Task GivePromoCodesToCustomersWithPreferenceAsync(GivePromoCodeRequest request) + public async Task> GivePromoCodesToCustomersWithPreferenceAsync(GivePromoCodeRequest request) { - //TODO: Создать промокод и выдать его клиентам с указанным предпочтением - throw new NotImplementedException(); + // TODO: Создать промокод и выдать его клиентам с указанным предпочтением + Guid promoCodeId; + try + { + var preferences = await _preferenceRepository.GetAllAsync(); + var preference = preferences.Where(p => p.Name == request.Preference).FirstOrDefault(); + + PromoCode promoCode = new() + { + Code = request.PromoCode, + ServiceInfo = request.ServiceInfo, + BeginDate = DateTime.Now, + EndDate = DateTime.Now, + PartnerName = request.PartnerName, + Preference = preference, + Customers = preference.Customers + }; + + promoCodeId = await _promoCodesRepository.AddAsync(promoCode); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + return Ok(promoCodeId); } } } \ No newline at end of file diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/PromoCodeFactory.WebHost.csproj b/Homeworks/EF/src/PromoCodeFactory.WebHost/PromoCodeFactory.WebHost.csproj index 4bb08b6e..14df811f 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/PromoCodeFactory.WebHost.csproj +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/PromoCodeFactory.WebHost.csproj @@ -12,6 +12,14 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs b/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs index eb69134e..af4b78ae 100644 --- a/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs +++ b/Homeworks/EF/src/PromoCodeFactory.WebHost/Startup.cs @@ -56,8 +56,16 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataCont { app.UseDeveloperExceptionPage(); // 3. База должна удаляться и создаваться каждый раз - dbContext.Database.EnsureDeleted(); - dbContext.Database.EnsureCreated(); + // 8. удаление на каждый запуск уже не должно происходить + //dbContext.Database.EnsureDeleted(); + //dbContext.Database.EnsureCreated(); + + // 8. реализовать две миграции + // начальную миграцию: + // dotnet ef migrations add InitialCreate --project "...\ASP.NET\Homeworks\EF\src\PromoCodeFactory.DataAccess\PromoCodeFactory.DataAccess.csproj" + // миграцию с изменением: + // dotnet ef migrations add AddCustomerPromoCodesTable --project "...\ASP.NET\Homeworks\EF\src\PromoCodeFactory.DataAccess\PromoCodeFactory.DataAccess.csproj" + dbContext.Database.Migrate(); } else {