diff --git a/Diner/Diner.sln b/Diner/Diner.sln index d17a1a1..ff29455 100644 --- a/Diner/Diner.sln +++ b/Diner/Diner.sln @@ -13,7 +13,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DinerBusinessLogic", "..\Ab EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DinerListImplement", "AbstractShopListImplement\DinerListImplement.csproj", "{A24E7474-4B43-4E81-A6BF-2B7323D5C26A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DinerFileImplement", "DinerFileImplement\DinerFileImplement.csproj", "{BF814E5C-E62C-4BFC-9B14-3D2F97F21CE6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DinerFileImplement", "DinerFileImplement\DinerFileImplement.csproj", "{BF814E5C-E62C-4BFC-9B14-3D2F97F21CE6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DinerDataBaseImplement", "DinerDataBaseImplement\DinerDataBaseImplement.csproj", "{3AC09806-4792-4A84-BCB8-87B29E0E1C8A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -45,6 +47,10 @@ Global {BF814E5C-E62C-4BFC-9B14-3D2F97F21CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU {BF814E5C-E62C-4BFC-9B14-3D2F97F21CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU {BF814E5C-E62C-4BFC-9B14-3D2F97F21CE6}.Release|Any CPU.Build.0 = Release|Any CPU + {3AC09806-4792-4A84-BCB8-87B29E0E1C8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AC09806-4792-4A84-BCB8-87B29E0E1C8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AC09806-4792-4A84-BCB8-87B29E0E1C8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AC09806-4792-4A84-BCB8-87B29E0E1C8A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Diner/Diner/DinerView.csproj b/Diner/Diner/DinerView.csproj index a7a34dc..ebcc4c3 100644 --- a/Diner/Diner/DinerView.csproj +++ b/Diner/Diner/DinerView.csproj @@ -9,12 +9,17 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/Diner/Diner/Program.cs b/Diner/Diner/Program.cs index 4f4d18c..5eedbb6 100644 --- a/Diner/Diner/Program.cs +++ b/Diner/Diner/Program.cs @@ -1,6 +1,6 @@ using DinerContracts.BusinessLogicsContracts; using DinerContracts.StoragesContracts; -using DinerFileImplement.Implements; +using DinerDataBaseImplement.Implements; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; diff --git a/Diner/DinerDataBaseImplement/DinerDataBaseImplement.csproj b/Diner/DinerDataBaseImplement/DinerDataBaseImplement.csproj new file mode 100644 index 0000000..b38577a --- /dev/null +++ b/Diner/DinerDataBaseImplement/DinerDataBaseImplement.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/Diner/DinerDataBaseImplement/DinerDatabase.cs b/Diner/DinerDataBaseImplement/DinerDatabase.cs new file mode 100644 index 0000000..02c1ce1 --- /dev/null +++ b/Diner/DinerDataBaseImplement/DinerDatabase.cs @@ -0,0 +1,21 @@ +using DinerDataBaseImplement.Models; +using Microsoft.EntityFrameworkCore; + +namespace DinerDataBaseImplement +{ + public class DinerDatabase : DbContext + { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (optionsBuilder.IsConfigured == false) + { + optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-BUS07H5\SQLEXPRESS;Initial Catalog=DinerDatabaseFull;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True"); + } + base.OnConfiguring(optionsBuilder); + } + public virtual DbSet Components { set; get; } + public virtual DbSet Snacks { set; get; } + public virtual DbSet SnackComponents { set; get; } + public virtual DbSet Orders { set; get; } + } +} diff --git a/Diner/DinerDataBaseImplement/Implements/ComponentStorage.cs b/Diner/DinerDataBaseImplement/Implements/ComponentStorage.cs new file mode 100644 index 0000000..3546f99 --- /dev/null +++ b/Diner/DinerDataBaseImplement/Implements/ComponentStorage.cs @@ -0,0 +1,78 @@ +using DinerContracts.BindingModels; +using DinerContracts.SearchModels; +using DinerContracts.StoragesContracts; +using DinerContracts.ViewModels; +using DinerDataBaseImplement.Models; + +namespace DinerDataBaseImplement.Implements +{ + public class ComponentStorage : IComponentStorage + { + public List GetFullList() + { + using var context = new DinerDatabase(); + return context.Components + .Select(x => x.GetViewModel) + .ToList(); + } + public List GetFilteredList(ComponentSearchModel model) + { + if (string.IsNullOrEmpty(model.ComponentName)) + { + return new(); + } + using var context = new DinerDatabase(); + return context.Components + .Where(x => x.ComponentName.Contains(model.ComponentName)) + .Select(x => x.GetViewModel) + .ToList(); + } + public ComponentViewModel? GetElement(ComponentSearchModel model) + { + if (string.IsNullOrEmpty(model.ComponentName) && !model.Id.HasValue) + { + return null; + } + using var context = new DinerDatabase(); + return context.Components + .FirstOrDefault(x => + (!string.IsNullOrEmpty(model.ComponentName) && x.ComponentName == model.ComponentName) || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; + } + public ComponentViewModel? Insert(ComponentBindingModel model) + { + var newComponent = Component.Create(model); + if (newComponent == null) + { + return null; + } + using var context = new DinerDatabase(); + context.Components.Add(newComponent); + context.SaveChanges(); + return newComponent.GetViewModel; + } + public ComponentViewModel? Update(ComponentBindingModel model) + { + using var context = new DinerDatabase(); + var component = context.Components.FirstOrDefault(x => x.Id == model.Id); + if (component == null) + { + return null; + } + component.Update(model); + context.SaveChanges(); + return component.GetViewModel; + } + public ComponentViewModel? Delete(ComponentBindingModel model) + { + using var context = new DinerDatabase(); + var element = context.Components.FirstOrDefault(rec => rec.Id == model.Id); + if (element != null) + { + context.Components.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + } +} diff --git a/Diner/DinerDataBaseImplement/Implements/OrderStorage.cs b/Diner/DinerDataBaseImplement/Implements/OrderStorage.cs new file mode 100644 index 0000000..8931025 --- /dev/null +++ b/Diner/DinerDataBaseImplement/Implements/OrderStorage.cs @@ -0,0 +1,93 @@ +using DinerContracts.BindingModels; +using DinerContracts.SearchModels; +using DinerContracts.StoragesContracts; +using DinerContracts.ViewModels; +using DinerDataBaseImplement.Models; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DinerDataBaseImplement.Implements +{ + public class OrderStorage : IOrderStorage + { + public List GetFullList() + { + using var context = new DinerDatabase(); + + return context.Orders + .Include(x => x.Snack) + .Select(x => x.GetViewModel) + .ToList(); + } + public List GetFilteredList(OrderSearchModel model) + { + if (!model.Id.HasValue) + { + return new(); + } + using var context = new DinerDatabase(); + return context.Orders + .Include(x => x.Snack) + .Where(x => x.Id == model.Id) + .Select(x => x.GetViewModel) + .ToList(); + } + public OrderViewModel? GetElement(OrderSearchModel model) + { + if (!model.Id.HasValue) + { + return null; + } + using var context = new DinerDatabase(); + return context.Orders.Include(x => x.Snack) + .FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id)?.GetViewModel; + } + public OrderViewModel? Insert(OrderBindingModel model) + { + using var context = new DinerDatabase(); + var newOrder = Order.Create(model); + if (newOrder == null) + { + return null; + } + context.Orders.Add(newOrder); + context.SaveChanges(); + return context.Orders.Include(x => x.Snack) + .FirstOrDefault(x => x.Id == newOrder.Id)?.GetViewModel; ; + } + public OrderViewModel? Update(OrderBindingModel model) + { + using var context = new DinerDatabase(); + var order = context.Orders.FirstOrDefault(rec => rec.Id == model.Id); + if (order == null) + { + return null; + } + order.Update(model); + context.SaveChanges(); + + return context.Orders + .Include(x => x.Snack) + .FirstOrDefault(x => x.Id == model.Id)? + .GetViewModel; + } + public OrderViewModel? Delete(OrderBindingModel model) + { + using var context = new DinerDatabase(); + var element = context.Orders + .FirstOrDefault(x => x.Id == model.Id); + + if (element != null) + { + context.Orders.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + } +} diff --git a/Diner/DinerDataBaseImplement/Implements/SnackStorage.cs b/Diner/DinerDataBaseImplement/Implements/SnackStorage.cs new file mode 100644 index 0000000..334ed0a --- /dev/null +++ b/Diner/DinerDataBaseImplement/Implements/SnackStorage.cs @@ -0,0 +1,100 @@ +using DinerContracts.BindingModels; +using DinerContracts.SearchModels; +using DinerContracts.StoragesContracts; +using DinerContracts.ViewModels; +using DinerDataBaseImplement.Models; +using Microsoft.EntityFrameworkCore; + +namespace DinerDataBaseImplement.Implements +{ + public class SnackStorage : ISnackStorage + { + public List GetFullList() + { + using var context = new DinerDatabase(); + return context.Snacks + .Include(x => x.Components) + .ThenInclude(x => x.Component) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + public List GetFilteredList(SnackSearchModel model) + { + if (string.IsNullOrEmpty(model.SnackName)) + { + return new(); + } + using var context = new DinerDatabase(); + return context.Snacks + .Include(x => x.Components) + .ThenInclude(x => x.Component) + .Where(x => x.SnackName.Contains(model.SnackName)) + .ToList() + .Select(x => x.GetViewModel).ToList(); + } + public SnackViewModel? GetElement(SnackSearchModel model) + { + if (string.IsNullOrEmpty(model.SnackName) && + !model.Id.HasValue) + { + return null; + } + using var context = new DinerDatabase(); + return context.Snacks + .Include(x => x.Components) + .ThenInclude(x => x.Component) + .FirstOrDefault(x => (!string.IsNullOrEmpty(model.SnackName) && x.SnackName == model.SnackName) || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; + } + public SnackViewModel? Insert(SnackBindingModel model) + { + using var context = new DinerDatabase(); + var newSnack = Snack.Create(context, model); + if (newSnack == null) + { + return null; + } + context.Snacks.Add(newSnack); + context.SaveChanges(); + return newSnack.GetViewModel; + } + public SnackViewModel? Update(SnackBindingModel model) + { + using var context = new DinerDatabase(); + using var transaction = context.Database.BeginTransaction(); + try + { + var snack = context.Snacks.FirstOrDefault(rec => rec.Id == model.Id); + if (snack == null) + { + return null; + } + snack.Update(model); + context.SaveChanges(); + snack.UpdateComponents(context, model); + transaction.Commit(); + return snack.GetViewModel; + } + catch + { + transaction.Rollback(); + throw; + } + } + public SnackViewModel? Delete(SnackBindingModel model) + { + using var context = new DinerDatabase(); + var element = context.Snacks + .Include(x => x.Components) + .Include(x => x.Orders) + .FirstOrDefault(rec => rec.Id == model.Id); + if (element != null) + { + context.Snacks.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + } +} diff --git a/Diner/DinerDataBaseImplement/Models/Component.cs b/Diner/DinerDataBaseImplement/Models/Component.cs new file mode 100644 index 0000000..c6e1401 --- /dev/null +++ b/Diner/DinerDataBaseImplement/Models/Component.cs @@ -0,0 +1,56 @@ +using DinerContracts.BindingModels; +using DinerContracts.ViewModels; +using DinerDataModels.Models; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; + +namespace DinerDataBaseImplement.Models +{ + public class Component : IComponentModel + { + public int Id { get; private set; } + [Required] + public string ComponentName { get; private set; } = string.Empty; + [Required] + public double Cost { get; set; } + [ForeignKey("ComponentId")] + public virtual List SnackComponents { get; set; } = new(); + public static Component? Create(ComponentBindingModel model) + { + if (model == null) + { + return null; + } + return new Component() + { + Id = model.Id, + ComponentName = model.ComponentName, + Cost = model.Cost + }; + } + public static Component Create(ComponentViewModel model) + { + return new Component + { + Id = model.Id, + ComponentName = model.ComponentName, + Cost = model.Cost + }; + } + public void Update(ComponentBindingModel model) + { + if (model == null) + { + return; + } + ComponentName = model.ComponentName; + Cost = model.Cost; + } + public ComponentViewModel GetViewModel => new() + { + Id = Id, + ComponentName = ComponentName, + Cost = Cost + }; + } +} diff --git a/Diner/DinerDataBaseImplement/Models/Order.cs b/Diner/DinerDataBaseImplement/Models/Order.cs new file mode 100644 index 0000000..9c044ee --- /dev/null +++ b/Diner/DinerDataBaseImplement/Models/Order.cs @@ -0,0 +1,67 @@ + +using DinerContracts.BindingModels; +using DinerContracts.ViewModels; +using DinerDataModels.Enum; +using DinerDataModels.Models; +using System.ComponentModel.DataAnnotations; +using System.Xml.Linq; + +namespace DinerDataBaseImplement.Models +{ + public class Order : IOrderModel + { + public int Id { get; private set; } + [Required] + public int SnackId { get; private set; } + [Required] + public int Count { get; private set; } + [Required] + public double Sum { get; private set; } + [Required] + public OrderStatus Status { get; private set; } + [Required] + public DateTime DateCreate { get; private set; } + + public DateTime? DateImplement { get; private set; } + + public virtual Snack Snack { get; set; } + public static Order? Create(OrderBindingModel? model) + { + if (model == null) + { + return null; + } + return new Order() + { + Id = model.Id, + SnackId = model.SnackId, + Count = model.Count, + Sum = model.Sum, + Status = model.Status, + DateCreate = model.DateCreate, + DateImplement = model.DateImplement + }; + } + public void Update(OrderBindingModel? model) + { + if (model == null) + { + return; + } + Sum = model.Sum; + Status = model.Status; + DateImplement = model.DateImplement; + } + public OrderViewModel GetViewModel => new() + { + Id = Id, + SnackId = SnackId, + Count = Count, + Sum = Sum, + Status = Status, + DateCreate = DateCreate, + DateImplement = DateImplement, + SnackName = Snack.SnackName + }; + } +} diff --git a/Diner/DinerDataBaseImplement/Models/Snack.cs b/Diner/DinerDataBaseImplement/Models/Snack.cs new file mode 100644 index 0000000..50f99f8 --- /dev/null +++ b/Diner/DinerDataBaseImplement/Models/Snack.cs @@ -0,0 +1,89 @@ +using DinerContracts.BindingModels; +using DinerContracts.ViewModels; +using DinerDataModels.Models; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DinerDataBaseImplement.Models +{ + public class Snack : ISnackModel + { + public int Id { get; set; } + [Required] + public string SnackName { get; set; } = string.Empty; + [Required] + public double Price { get; set; } + private Dictionary? _snackComponents = null; + [NotMapped] + public Dictionary SnackComponents + { + get + { + if (_snackComponents == null) + { + _snackComponents = Components + .ToDictionary(recPC => recPC.ComponentId, recPC => (recPC.Component as IComponentModel, recPC.Count)); + } + return _snackComponents; + } + } + [ForeignKey("SnackId")] + public virtual List Components { get; set; } = new(); + [ForeignKey("SnackId")] + public virtual List Orders { get; set; } = new(); + public static Snack Create(DinerDatabase context, SnackBindingModel model) + { + return new Snack() + { + Id = model.Id, + SnackName = model.SnackName, + Price = model.Price, + Components = model.SnackComponents.Select(x => new SnackComponent + { + Component = context.Components.First(y => y.Id == x.Key), + Count = x.Value.Item2 + }).ToList() + }; + } + public void Update(SnackBindingModel model) + { + SnackName = model.SnackName; + Price = model.Price; + } + public SnackViewModel GetViewModel => new() + { + Id = Id, + SnackName = SnackName, + Price = Price, + SnackComponents = SnackComponents + }; + public void UpdateComponents(DinerDatabase context, SnackBindingModel model) + { + var snackComponents = context.SnackComponents.Where(rec => rec.SnackId == model.Id).ToList(); + if (snackComponents != null && snackComponents.Count > 0) + { // удалили те, которых нет в модели + context.SnackComponents.RemoveRange(snackComponents.Where(rec => !model.SnackComponents.ContainsKey(rec.ComponentId))); + context.SaveChanges(); + // обновили количество у существующих записей + foreach (var updateComponent in snackComponents) + { + updateComponent.Count = model.SnackComponents[updateComponent.ComponentId].Item2; + model.SnackComponents.Remove(updateComponent.ComponentId); + } + context.SaveChanges(); + } + var snack = context.Snacks.First(x => x.Id == Id); + foreach (var pc in model.SnackComponents) + { + context.SnackComponents.Add(new SnackComponent + { + Snack = snack, + Component = context.Components.First(x => x.Id == pc.Key), + Count = pc.Value.Item2 + }); + context.SaveChanges(); + } + _snackComponents = null; + } + } +} diff --git a/Diner/DinerDataBaseImplement/Models/SnackComponent.cs b/Diner/DinerDataBaseImplement/Models/SnackComponent.cs new file mode 100644 index 0000000..f137677 --- /dev/null +++ b/Diner/DinerDataBaseImplement/Models/SnackComponent.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DinerDataBaseImplement.Models +{ + public class SnackComponent + { + public int Id { get; set; } + [Required] + public int SnackId { get; set; } + [Required] + public int ComponentId { get; set; } + [Required] + public int Count { get; set; } + public virtual Component Component { get; set; } = new(); + public virtual Snack Snack { get; set; } = new(); + } +}