diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/GarmentFactoryDatabase.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/GarmentFactoryDatabase.cs index e0e142d..1269dab 100644 --- a/GarmentFactory/GarmentFactoryDatabaseImplement/GarmentFactoryDatabase.cs +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/GarmentFactoryDatabase.cs @@ -1,5 +1,5 @@ -using Microsoft.EntityFrameworkCore; -using GarmentFactoryDatabaseImplement.Models; +using GarmentFactoryDatabaseImplement.Models; +using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; @@ -14,7 +14,7 @@ namespace GarmentFactoryDatabaseImplement { if (optionsBuilder.IsConfigured == false) { - optionsBuilder.UseSqlServer(@"Data Source=localhost\SQLEXPRESS;Initial Catalog=GarmentFactoryDatabaseFull;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True"); + optionsBuilder.UseSqlServer(@"Data Source=localhost\SQLEXPRESS01;Initial Catalog=GarmentFactoryDatabaseFulll;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True"); } base.OnConfiguring(optionsBuilder); } @@ -22,5 +22,8 @@ namespace GarmentFactoryDatabaseImplement public virtual DbSet Textiles { set; get; } public virtual DbSet TextileComponents { set; get; } public virtual DbSet Orders { set; get; } - } + public virtual DbSet Shops { set; get; } + + public virtual DbSet ShopTextiles { set; get; } + } } diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Implements/ShopStorage.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Implements/ShopStorage.cs new file mode 100644 index 0000000..3e3fb8e --- /dev/null +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Implements/ShopStorage.cs @@ -0,0 +1,146 @@ +using GarmentFactoryContracts.BindingModels; +using GarmentFactoryContracts.SearchModels; +using GarmentFactoryContracts.StoragesContracts; +using GarmentFactoryContracts.ViewModels; +using GarmentFactoryDatabaseImplement.Models; +using GarmentFactoryDataModels.Models; +using Microsoft.EntityFrameworkCore; + +namespace GarmentFactoryDatabaseImplement.Implements +{ + public class ShopStorage : IShopStorage + { + public List GetFullList() + { + using var context = new GarmentFactoryDatabase(); + return context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFilteredList(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName)) + { + return new(); + } + using var context = new GarmentFactoryDatabase(); + return context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .Where(x => x.ShopName.Contains(model.ShopName)) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + + public ShopViewModel? GetElement(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue) + { + return null; + } + using var context = new GarmentFactoryDatabase(); + return context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .FirstOrDefault(x => (!string.IsNullOrEmpty(model.ShopName) && x.ShopName == model.ShopName) || + (model.Id.HasValue && x.Id == model.Id)) + ?.GetViewModel; + } + + public ShopViewModel? Insert(ShopBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + var newShop = Shop.Create(context, model); + if (newShop == null) + { + return null; + } + context.Shops.Add(newShop); + context.SaveChanges(); + return newShop.GetViewModel; + } + + public ShopViewModel? Update(ShopBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + 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.UpdateTextiles(context, model); + transaction.Commit(); + return shop.GetViewModel; + } + catch + { + transaction.Rollback(); + throw; + } + } + + public ShopViewModel? Delete(ShopBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + var element = context.Shops + .Include(x => x.Textiles) + .FirstOrDefault(rec => rec.Id == model.Id); + if (element != null) + { + context.Shops.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + + public bool MakeSale(ITextileModel model, int count) + { + using var context = new GarmentFactoryDatabase(); + using var transaction = context.Database.BeginTransaction(); + try + { + foreach (var shop in context.Shops.Include(x => x.Textiles).ThenInclude(x => x.Textile) + .Where(x => x.Textiles.Any(x => x.TextileId == model.Id)) + .ToList()) + { + var textile = shop.ShopTextiles[model.Id]; + int min = Math.Min(textile.Item2, count); + if (min == textile.Item2) + { + shop.ShopTextiles.Remove(model.Id); + } + else + { + shop.ShopTextiles[model.Id] = (textile.Item1, textile.Item2 - min); + } + shop.UpdateTextiles(context, new() { Id = shop.Id, ShopTextiles = shop.ShopTextiles }); + count -= min; + if (count == 0) + { + context.SaveChanges(); + transaction.Commit(); + return true; + } + } + transaction.Rollback(); + return false; + } + catch + { + transaction.Rollback(); + throw; + } + } + } +} diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240319190105_InitialCreate.Designer.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240419160846_ImplementerAddition.Designer.cs similarity index 67% rename from GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240319190105_InitialCreate.Designer.cs rename to GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240419160846_ImplementerAddition.Designer.cs index 84c4a19..43b0609 100644 --- a/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240319190105_InitialCreate.Designer.cs +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240419160846_ImplementerAddition.Designer.cs @@ -12,8 +12,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace GarmentFactoryDatabaseImplement.Migrations { [DbContext(typeof(GarmentFactoryDatabase))] - [Migration("20240319190105_InitialCreate")] - partial class InitialCreate + [Migration("20240419160846_ImplementerAddition")] + partial class ImplementerAddition { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -78,6 +78,59 @@ namespace GarmentFactoryDatabaseImplement.Migrations b.ToTable("Orders"); }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Shop", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateOpening") + .HasColumnType("datetime2"); + + b.Property("ShopName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TextilesMaximum") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Shops"); + }); + + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.ShopTextile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("ShopId") + .HasColumnType("int"); + + b.Property("TextileId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ShopId"); + + b.HasIndex("TextileId"); + + b.ToTable("ShopTextiles"); + }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Textile", b => { b.Property("Id") @@ -135,6 +188,25 @@ namespace GarmentFactoryDatabaseImplement.Migrations b.Navigation("Textile"); }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.ShopTextile", b => + { + b.HasOne("GarmentFactoryDatabaseImplement.Models.Shop", "Shop") + .WithMany("Textiles") + .HasForeignKey("ShopId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GarmentFactoryDatabaseImplement.Models.Textile", "Textile") + .WithMany("ShopTextiles") + .HasForeignKey("TextileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Shop"); + + b.Navigation("Textile"); + }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.TextileComponent", b => { b.HasOne("GarmentFactoryDatabaseImplement.Models.Component", "Component") @@ -159,11 +231,18 @@ namespace GarmentFactoryDatabaseImplement.Migrations b.Navigation("TextileComponents"); }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Shop", b => + { + b.Navigation("Textiles"); + }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Textile", b => { b.Navigation("Components"); b.Navigation("Orders"); + + b.Navigation("ShopTextiles"); }); #pragma warning restore 612, 618 } diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240319190105_InitialCreate.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240419160846_ImplementerAddition.cs similarity index 65% rename from GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240319190105_InitialCreate.cs rename to GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240419160846_ImplementerAddition.cs index b4c0f3d..1dda64e 100644 --- a/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240319190105_InitialCreate.cs +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/20240419160846_ImplementerAddition.cs @@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace GarmentFactoryDatabaseImplement.Migrations { /// - public partial class InitialCreate : Migration + public partial class ImplementerAddition : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -25,6 +25,22 @@ namespace GarmentFactoryDatabaseImplement.Migrations table.PrimaryKey("PK_Components", x => x.Id); }); + 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), + DateOpening = table.Column(type: "datetime2", nullable: false), + TextilesMaximum = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Shops", x => x.Id); + }); + migrationBuilder.CreateTable( name: "Textiles", columns: table => new @@ -63,6 +79,33 @@ namespace GarmentFactoryDatabaseImplement.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "ShopTextiles", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ShopId = table.Column(type: "int", nullable: false), + TextileId = table.Column(type: "int", nullable: false), + Count = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ShopTextiles", x => x.Id); + table.ForeignKey( + name: "FK_ShopTextiles_Shops_ShopId", + column: x => x.ShopId, + principalTable: "Shops", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ShopTextiles_Textiles_TextileId", + column: x => x.TextileId, + principalTable: "Textiles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "TextileComponents", columns: table => new @@ -95,6 +138,16 @@ namespace GarmentFactoryDatabaseImplement.Migrations table: "Orders", column: "TextileId"); + migrationBuilder.CreateIndex( + name: "IX_ShopTextiles_ShopId", + table: "ShopTextiles", + column: "ShopId"); + + migrationBuilder.CreateIndex( + name: "IX_ShopTextiles_TextileId", + table: "ShopTextiles", + column: "TextileId"); + migrationBuilder.CreateIndex( name: "IX_TextileComponents_ComponentId", table: "TextileComponents", @@ -112,9 +165,15 @@ namespace GarmentFactoryDatabaseImplement.Migrations migrationBuilder.DropTable( name: "Orders"); + migrationBuilder.DropTable( + name: "ShopTextiles"); + migrationBuilder.DropTable( name: "TextileComponents"); + migrationBuilder.DropTable( + name: "Shops"); + migrationBuilder.DropTable( name: "Components"); diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/GarmentFactoryDatabaseModelSnapshot.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/GarmentFactoryDatabaseModelSnapshot.cs index 73aa3d1..4c8b718 100644 --- a/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/GarmentFactoryDatabaseModelSnapshot.cs +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Migrations/GarmentFactoryDatabaseModelSnapshot.cs @@ -75,6 +75,59 @@ namespace GarmentFactoryDatabaseImplement.Migrations b.ToTable("Orders"); }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Shop", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateOpening") + .HasColumnType("datetime2"); + + b.Property("ShopName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TextilesMaximum") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Shops"); + }); + + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.ShopTextile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("ShopId") + .HasColumnType("int"); + + b.Property("TextileId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ShopId"); + + b.HasIndex("TextileId"); + + b.ToTable("ShopTextiles"); + }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Textile", b => { b.Property("Id") @@ -132,6 +185,25 @@ namespace GarmentFactoryDatabaseImplement.Migrations b.Navigation("Textile"); }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.ShopTextile", b => + { + b.HasOne("GarmentFactoryDatabaseImplement.Models.Shop", "Shop") + .WithMany("Textiles") + .HasForeignKey("ShopId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GarmentFactoryDatabaseImplement.Models.Textile", "Textile") + .WithMany("ShopTextiles") + .HasForeignKey("TextileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Shop"); + + b.Navigation("Textile"); + }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.TextileComponent", b => { b.HasOne("GarmentFactoryDatabaseImplement.Models.Component", "Component") @@ -156,11 +228,18 @@ namespace GarmentFactoryDatabaseImplement.Migrations b.Navigation("TextileComponents"); }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Shop", b => + { + b.Navigation("Textiles"); + }); + modelBuilder.Entity("GarmentFactoryDatabaseImplement.Models.Textile", b => { b.Navigation("Components"); b.Navigation("Orders"); + + b.Navigation("ShopTextiles"); }); #pragma warning restore 612, 618 } diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Shop.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Shop.cs new file mode 100644 index 0000000..1b679a5 --- /dev/null +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Shop.cs @@ -0,0 +1,115 @@ +using GarmentFactoryContracts.BindingModels; +using GarmentFactoryContracts.ViewModels; +using GarmentFactoryDataModels.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 GarmentFactoryDatabaseImplement.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 DateOpening { get; set; } + + [Required] + public int TextilesMaximum { get; set; } + + private Dictionary? _shopTextiles = null; + + [NotMapped] + public Dictionary ShopTextiles + { + get + { + if (_shopTextiles == null) + { + _shopTextiles = Textiles + .ToDictionary(x => x.TextileId, x => (x.Textile as ITextileModel, x.Count)); + } + return _shopTextiles; + } + } + + [ForeignKey("ShopId")] + public virtual List Textiles { get; set; } = new(); + + public static Shop Create(GarmentFactoryDatabase context, ShopBindingModel model) + { + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + Address = model.Address, + DateOpening = model.DateOpening, + TextilesMaximum = model.TextilesMaximum, + Textiles = model.ShopTextiles.Select(x => new ShopTextile + { + Textile = context.Textiles.First(y => y.Id == x.Key), + Count = x.Value.Item2 + }).ToList() + }; + } + + public void Update(ShopBindingModel model) + { + ShopName = model.ShopName; + Address = model.Address; + DateOpening = model.DateOpening; + TextilesMaximum = model.TextilesMaximum; + } + + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + Address = Address, + DateOpening = DateOpening, + TextilesMaximum = TextilesMaximum, + ShopTextiles = ShopTextiles + }; + + public void UpdateTextiles(GarmentFactoryDatabase context, ShopBindingModel model) + { + var shopTextiles = context.ShopTextiles.Where(rec => rec.ShopId == model.Id).ToList(); + if (shopTextiles != null && shopTextiles.Count > 0) + { + context.ShopTextiles.RemoveRange(shopTextiles.Where(rec => !model.ShopTextiles.ContainsKey(rec.TextileId))); + context.SaveChanges(); + foreach (var updateTextile in shopTextiles) + { + if (model.ShopTextiles.ContainsKey(updateTextile.TextileId)) + { + updateTextile.Count = model.ShopTextiles[updateTextile.TextileId].Item2; + model.ShopTextiles.Remove(updateTextile.TextileId); + } + } + context.SaveChanges(); + } + var shop = context.Shops.First(x => x.Id == Id); + foreach (var ic in model.ShopTextiles) + { + context.ShopTextiles.Add(new ShopTextile + { + Shop = shop, + Textile = context.Textiles.First(x => x.Id == ic.Key), + Count = ic.Value.Item2 + }); + context.SaveChanges(); + } + _shopTextiles = null; + } + } +} diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Models/ShopTextile.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Models/ShopTextile.cs new file mode 100644 index 0000000..6429cd2 --- /dev/null +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Models/ShopTextile.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GarmentFactoryDatabaseImplement.Models +{ + public class ShopTextile + { + public int Id { get; set; } + + [Required] + public int ShopId { get; set; } + + [Required] + public int TextileId { get; set; } + + [Required] + public int Count { get; set; } + + public virtual Textile Textile { get; set; } = new(); + + public virtual Shop Shop { get; set; } = new(); + } +} diff --git a/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Textile.cs b/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Textile.cs index 76aa3ce..5fc28fd 100644 --- a/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Textile.cs +++ b/GarmentFactory/GarmentFactoryDatabaseImplement/Models/Textile.cs @@ -34,7 +34,9 @@ namespace GarmentFactoryDatabaseImplement.Models public virtual List Components { get; set; } = new(); [ForeignKey("TextileId")] public virtual List Orders { get; set; } = new(); - public static Textile Create(GarmentFactoryDatabase context, + [ForeignKey("TextileId")] + public virtual List ShopTextiles { get; set; } = new(); + public static Textile Create(GarmentFactoryDatabase context, TextileBindingModel model) { return new Textile()