diff --git a/Shipyard/ShipyardDataBaseImplement/Implements/ShipStorage.cs b/Shipyard/ShipyardDataBaseImplement/Implements/ShipStorage.cs index 34c433b..0b85bcc 100644 --- a/Shipyard/ShipyardDataBaseImplement/Implements/ShipStorage.cs +++ b/Shipyard/ShipyardDataBaseImplement/Implements/ShipStorage.cs @@ -81,7 +81,7 @@ namespace ShipyardDataBaseImplement.Implements } product.Update(model); context.SaveChanges(); - product.UpdateComponents(context, model); + product.UpdateDetails(context, model); transaction.Commit(); return product.GetViewModel; } diff --git a/Shipyard/ShipyardDataBaseImplement/Implements/ShopStorage.cs b/Shipyard/ShipyardDataBaseImplement/Implements/ShopStorage.cs new file mode 100644 index 0000000..bda375f --- /dev/null +++ b/Shipyard/ShipyardDataBaseImplement/Implements/ShopStorage.cs @@ -0,0 +1,158 @@ +using Microsoft.EntityFrameworkCore; +using ShipyardContracts.BindingModels; +using ShipyardContracts.SearchModels; +using ShipyardContracts.StoragesContracts; +using ShipyardContracts.ViewModels; +using ShipyardDataBaseImplement.Models; +using ShipyardDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Runtime.ConstrainedExecution; +using System.Text; +using System.Threading.Tasks; + +namespace ShipyardDataBaseImplement.Implements +{ + public class ShopStorage : IShopStorage + { + public ShopViewModel? GetElement(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName) && + !model.Id.HasValue) + { + return null; + } + using var context = new ShipyardDataBase(); + return context.Shops + .Include(x => x.Ships) + .ThenInclude(x => x.Ship) + .FirstOrDefault(x => (!string.IsNullOrEmpty(model.ShopName) && + x.ShopName == model.ShopName) || + (model.Id.HasValue && x.Id == + model.Id)) + ?.GetViewModel; + } + + public List GetFilteredList(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName)) + { + return new(); + } + using var context = new ShipyardDataBase(); + return context.Shops + .Include(x => x.Ships) + .ThenInclude(x => x.Ship) + .Where(x => x.ShopName.Contains(model.ShopName)) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFullList() + { + using var context = new ShipyardDataBase(); + return context.Shops.Include(x => x.Ships) + .ThenInclude(x => x.Ship) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + + public ShopViewModel? Insert(ShopBindingModel model) + { + using var context = new ShipyardDataBase(); + var newProduct = Shop.Create(context, model); + if (newProduct == null) + { + return null; + } + context.Shops.Add(newProduct); + context.SaveChanges(); + return newProduct.GetViewModel; + } + + public ShopViewModel? Update(ShopBindingModel model) + { + using var context = new ShipyardDataBase(); + using var transaction = context.Database.BeginTransaction(); + try + { + var shop = context.Shops.FirstOrDefault(rec => + rec.Id == model.Id); + if (shop == null) + { + return null; + } + shop.Update(model); + context.SaveChanges(); + shop.UpdateShips(context, model); + transaction.Commit(); + return shop.GetViewModel; + } + catch + { + transaction.Rollback(); + throw; + } + } + public ShopViewModel? Delete(ShopBindingModel model) + { + using var context = new ShipyardDataBase(); + var element = context.Shops + .Include(x => x.Ships) + .FirstOrDefault(rec => rec.Id == model.Id); + if (element != null) + { + context.Shops.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + public bool SellShips(IShipModel model, int count) + { + using var context = new ShipyardDataBase(); + using var transaction = context.Database.BeginTransaction(); + try + { + List shopsWithShip = context.Shops.Include(x => x.Ships).ThenInclude(x => x.Ship).Where(x => x.Ships.Any(x => x.ShipId == model.Id)).ToList(); + foreach (var shop in shopsWithShip) + { + int carInShopCount = shop.ShopShips[model.Id].Item2; + if (count - carInShopCount >= 0) + { + count -= carInShopCount; + context.ShopShips.Remove(shop.Ships.FirstOrDefault(x => x.ShipId == model.Id)!); + shop.ShopShips.Remove(model.Id); + } + else + { + shop.ShopShips[model.Id] = (model, carInShopCount - count); + count = 0; + shop.UpdateShips(context, new() + { + Id = shop.Id, + ShopShips = shop.ShopShips + }); + } + if (count == 0) + { + context.SaveChanges(); + transaction.Commit(); + return true; + } + } + transaction.Rollback(); + return false; + } + catch + { + transaction.Rollback(); + throw; + } + } + } +} diff --git a/Shipyard/ShipyardDataBaseImplement/Migrations/20230319132059_ShopMigration.Designer.cs b/Shipyard/ShipyardDataBaseImplement/Migrations/20230319132059_ShopMigration.Designer.cs new file mode 100644 index 0000000..7970331 --- /dev/null +++ b/Shipyard/ShipyardDataBaseImplement/Migrations/20230319132059_ShopMigration.Designer.cs @@ -0,0 +1,250 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ShipyardDataBaseImplement; + +#nullable disable + +namespace ShipyardDataBaseImplement.Migrations +{ + [DbContext(typeof(ShipyardDataBase))] + [Migration("20230319132059_ShopMigration")] + partial class ShopMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Detail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Cost") + .HasColumnType("float"); + + b.Property("DetailName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Details"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateImplement") + .HasColumnType("datetime2"); + + b.Property("ShipId") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Sum") + .HasColumnType("float"); + + b.HasKey("Id"); + + b.HasIndex("ShipId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Ship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Price") + .HasColumnType("float"); + + b.Property("ShipName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Ships"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.ShipDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("DetailId") + .HasColumnType("int"); + + b.Property("ShipId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("DetailId"); + + b.HasIndex("ShipId"); + + b.ToTable("ShipDetails"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Shop", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Capacity") + .HasColumnType("int"); + + b.Property("DateOpen") + .HasColumnType("datetime2"); + + b.Property("ShopName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Shops"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.ShopShip", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("ShipId") + .HasColumnType("int"); + + b.Property("ShopId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ShipId"); + + b.HasIndex("ShopId"); + + b.ToTable("ShopShips"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Order", b => + { + b.HasOne("ShipyardDataBaseImplement.Models.Ship", "Ship") + .WithMany("Orders") + .HasForeignKey("ShipId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ship"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.ShipDetail", b => + { + b.HasOne("ShipyardDataBaseImplement.Models.Detail", "Detail") + .WithMany("ShipDetails") + .HasForeignKey("DetailId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ShipyardDataBaseImplement.Models.Ship", "Ship") + .WithMany("Details") + .HasForeignKey("ShipId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Detail"); + + b.Navigation("Ship"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.ShopShip", b => + { + b.HasOne("ShipyardDataBaseImplement.Models.Ship", "Ship") + .WithMany("Ships") + .HasForeignKey("ShipId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ShipyardDataBaseImplement.Models.Shop", "Shop") + .WithMany("Ships") + .HasForeignKey("ShopId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ship"); + + b.Navigation("Shop"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Detail", b => + { + b.Navigation("ShipDetails"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Ship", b => + { + b.Navigation("Details"); + + b.Navigation("Orders"); + + b.Navigation("Ships"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Shop", b => + { + b.Navigation("Ships"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Shipyard/ShipyardDataBaseImplement/Migrations/20230319132059_ShopMigration.cs b/Shipyard/ShipyardDataBaseImplement/Migrations/20230319132059_ShopMigration.cs new file mode 100644 index 0000000..276c7a6 --- /dev/null +++ b/Shipyard/ShipyardDataBaseImplement/Migrations/20230319132059_ShopMigration.cs @@ -0,0 +1,78 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ShipyardDataBaseImplement.Migrations +{ + /// + public partial class ShopMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Shops", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ShopName = table.Column(type: "nvarchar(max)", nullable: false), + Address = table.Column(type: "nvarchar(max)", nullable: false), + DateOpen = table.Column(type: "datetime2", nullable: false), + Capacity = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Shops", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ShopShips", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ShopId = table.Column(type: "int", nullable: false), + ShipId = table.Column(type: "int", nullable: false), + Count = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ShopShips", x => x.Id); + table.ForeignKey( + name: "FK_ShopShips_Ships_ShipId", + column: x => x.ShipId, + principalTable: "Ships", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ShopShips_Shops_ShopId", + column: x => x.ShopId, + principalTable: "Shops", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ShopShips_ShipId", + table: "ShopShips", + column: "ShipId"); + + migrationBuilder.CreateIndex( + name: "IX_ShopShips_ShopId", + table: "ShopShips", + column: "ShopId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ShopShips"); + + migrationBuilder.DropTable( + name: "Shops"); + } + } +} diff --git a/Shipyard/ShipyardDataBaseImplement/Migrations/ShipyardDataBaseModelSnapshot.cs b/Shipyard/ShipyardDataBaseImplement/Migrations/ShipyardDataBaseModelSnapshot.cs index 8013b5f..25102ea 100644 --- a/Shipyard/ShipyardDataBaseImplement/Migrations/ShipyardDataBaseModelSnapshot.cs +++ b/Shipyard/ShipyardDataBaseImplement/Migrations/ShipyardDataBaseModelSnapshot.cs @@ -121,6 +121,59 @@ namespace ShipyardDataBaseImplement.Migrations b.ToTable("ShipDetails"); }); + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Shop", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Capacity") + .HasColumnType("int"); + + b.Property("DateOpen") + .HasColumnType("datetime2"); + + b.Property("ShopName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Shops"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.ShopShip", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("ShipId") + .HasColumnType("int"); + + b.Property("ShopId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ShipId"); + + b.HasIndex("ShopId"); + + b.ToTable("ShopShips"); + }); + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Order", b => { b.HasOne("ShipyardDataBaseImplement.Models.Ship", "Ship") @@ -151,6 +204,25 @@ namespace ShipyardDataBaseImplement.Migrations b.Navigation("Ship"); }); + modelBuilder.Entity("ShipyardDataBaseImplement.Models.ShopShip", b => + { + b.HasOne("ShipyardDataBaseImplement.Models.Ship", "Ship") + .WithMany("Ships") + .HasForeignKey("ShipId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ShipyardDataBaseImplement.Models.Shop", "Shop") + .WithMany("Ships") + .HasForeignKey("ShopId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ship"); + + b.Navigation("Shop"); + }); + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Detail", b => { b.Navigation("ShipDetails"); @@ -161,6 +233,13 @@ namespace ShipyardDataBaseImplement.Migrations b.Navigation("Details"); b.Navigation("Orders"); + + b.Navigation("Ships"); + }); + + modelBuilder.Entity("ShipyardDataBaseImplement.Models.Shop", b => + { + b.Navigation("Ships"); }); #pragma warning restore 612, 618 } diff --git a/Shipyard/ShipyardDataBaseImplement/Models/Ship.cs b/Shipyard/ShipyardDataBaseImplement/Models/Ship.cs index aaa5cdc..d400606 100644 --- a/Shipyard/ShipyardDataBaseImplement/Models/Ship.cs +++ b/Shipyard/ShipyardDataBaseImplement/Models/Ship.cs @@ -36,6 +36,8 @@ namespace ShipyardDataBaseImplement.Models public virtual List Details { get; set; } = new(); [ForeignKey("ShipId")] public virtual List Orders { get; set; } = new(); + [ForeignKey("ShipId")] + public virtual List Ships { get; set; } = new(); public static Ship Create(ShipyardDataBase context, ShipBindingModel model) { return new Ship() @@ -63,17 +65,16 @@ namespace ShipyardDataBaseImplement.Models Price = Price, ShipDetails = ShipDetails }; - public void UpdateComponents(ShipyardDataBase context, + public void UpdateDetails(ShipyardDataBase context, ShipBindingModel model) { var shipDetails = context.ShipDetails.Where(rec => rec.ShipId == model.Id).ToList(); if (shipDetails != null && shipDetails.Count > 0) - { // удалили те, которых нет в модели + { context.ShipDetails.RemoveRange(shipDetails.Where(rec => !model.ShipDetails.ContainsKey(rec.DetailId))); context.SaveChanges(); - // обновили количество у существующих записей foreach (var updateDetail in shipDetails) { updateDetail.Count = model.ShipDetails[updateDetail.DetailId].Item2; diff --git a/Shipyard/ShipyardDataBaseImplement/Models/Shop.cs b/Shipyard/ShipyardDataBaseImplement/Models/Shop.cs new file mode 100644 index 0000000..108e671 --- /dev/null +++ b/Shipyard/ShipyardDataBaseImplement/Models/Shop.cs @@ -0,0 +1,106 @@ +using ShipyardContracts.BindingModels; +using ShipyardContracts.ViewModels; +using ShipyardDataModels.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShipyardDataBaseImplement.Models +{ + public class Shop : IShopModel + { + public int Id { get; set; } + [Required] + public string ShopName { get; set; } = string.Empty; + [Required] + public string Address { get; set; } = string.Empty; + [Required] + public DateTime DateOpen { get; set; } + [Required] + public int Capacity { get; set; } + + private Dictionary? _shopShips = null; + + [NotMapped] + public Dictionary ShopShips + { + get + { + if (_shopShips == null) + { + _shopShips = Ships + .ToDictionary(recST => recST.ShipId, recST => (recST.Ship as IShipModel, recST.Count)); + } + return _shopShips; + } + } + [ForeignKey("ShopId")] + public virtual List Ships { get; set; } = new(); + public static Shop Create(ShipyardDataBase context, ShopBindingModel model) + { + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + Address = model.Address, + DateOpen = model.DateOpen, + Capacity = model.Capacity, + Ships = model.ShopShips.Select(x => new ShopShip + { + Ship = context.Ships.First(y => y.Id == x.Key), + Count = x.Value.Item2 + }).ToList() + }; + } + + public void Update(ShopBindingModel model) + { + ShopName = model.ShopName; + Address = model.Address; + DateOpen = model.DateOpen; + Capacity = model.Capacity; + } + + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + Address = Address, + DateOpen = DateOpen, + Capacity = Capacity, + ShopShips = ShopShips + }; + + public void UpdateShips(ShipyardDataBase context, ShopBindingModel model) + { + var shopShips = context.ShopShips.Where(rec => rec.ShipId == model.Id).ToList(); + if (shopShips != null && shopShips.Count > 0) + { + context.ShopShips.RemoveRange(shopShips.Where(rec => !model.ShopShips.ContainsKey(rec.ShipId))); + context.SaveChanges(); + foreach (var updateShip in shopShips) + { + updateShip.Count = model.ShopShips[updateShip.ShipId].Item2; + model.ShopShips.Remove(updateShip.ShipId); + } + context.SaveChanges(); + } + var shop = context.Shops.First(x => x.Id == Id); + foreach (var id in model.ShopShips) + { + context.ShopShips.Add(new ShopShip + { + Shop = shop, + Ship = context.Ships.First(x => x.Id == id.Key), + Count = id.Value.Item2 + }); + context.SaveChanges(); + } + _shopShips = null; + } + } +} diff --git a/Shipyard/ShipyardDataBaseImplement/Models/ShopShip.cs b/Shipyard/ShipyardDataBaseImplement/Models/ShopShip.cs new file mode 100644 index 0000000..35cdd89 --- /dev/null +++ b/Shipyard/ShipyardDataBaseImplement/Models/ShopShip.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShipyardDataBaseImplement.Models +{ + public class ShopShip + { + public int Id { get; set; } + + [Required] + public int ShopId { get; set; } + + [Required] + public int ShipId { get; set; } + + [Required] + public int Count { get; set; } + + public virtual Ship Ship { get; set; } = new(); + + public virtual Shop Shop { get; set; } = new(); + } +} diff --git a/Shipyard/ShipyardDataBaseImplement/ShipyardDataBase.cs b/Shipyard/ShipyardDataBaseImplement/ShipyardDataBase.cs index 0d85e8d..0c1dd15 100644 --- a/Shipyard/ShipyardDataBaseImplement/ShipyardDataBase.cs +++ b/Shipyard/ShipyardDataBaseImplement/ShipyardDataBase.cs @@ -23,6 +23,8 @@ namespace ShipyardDataBaseImplement public virtual DbSet Ships { set; get; } public virtual DbSet ShipDetails { set; get; } public virtual DbSet Orders { set; get; } + public virtual DbSet Shops { set; get; } + public virtual DbSet ShopShips { set; get; } } }