Третья усложнённая лабораторная работа. Релизовано сохранение в БД, попленение и списание требует фикса.

This commit is contained in:
abazov73 2023-05-15 09:39:07 +04:00
parent f50a1d0d82
commit 41e2b23042
8 changed files with 724 additions and 1 deletions

1
.gitignore vendored
View File

@ -398,3 +398,4 @@ FodyWeavers.xsd
# JetBrains Rider # JetBrains Rider
*.sln.iml *.sln.iml
/Confectionery/ImplementationExtensions

View File

@ -15,7 +15,7 @@ namespace ConfectioneryDataBaseImplement
{ {
if (optionsBuilder.IsConfigured == false) if (optionsBuilder.IsConfigured == false)
{ {
optionsBuilder.UseSqlServer(@"Data Source=localhost\SQLEXPRESS;Initial Catalog=ConfectioneryDatabaseFull;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True"); optionsBuilder.UseSqlServer(@"Data Source=localhost\SQLEXPRESS;Initial Catalog=ConfectioneryDatabaseHardLab;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True");
} }
base.OnConfiguring(optionsBuilder); base.OnConfiguring(optionsBuilder);
} }
@ -23,5 +23,7 @@ namespace ConfectioneryDataBaseImplement
public virtual DbSet<Pastry> Pastrys { set; get; } public virtual DbSet<Pastry> Pastrys { set; get; }
public virtual DbSet<PastryIngredient> PastryIngredients { set; get; } public virtual DbSet<PastryIngredient> PastryIngredients { set; get; }
public virtual DbSet<Order> Orders { set; get; } public virtual DbSet<Order> Orders { set; get; }
public virtual DbSet<Shop> Shops { set; get; }
public virtual DbSet<ShopPastry> ShopPastries { set; get; }
} }
} }

View File

@ -0,0 +1,185 @@
using ConfectioneryContracts.BindingModels;
using ConfectioneryContracts.SearchModels;
using ConfectioneryContracts.StoragesContracts;
using ConfectioneryContracts.ViewModels;
using ConfectioneryDataBaseImplement.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConfectioneryDataBaseImplement.Implements
{
public class ShopStorage : IShopStorage
{
public List<ShopViewModel> GetFullList()
{
using var context = new ConfectioneryDatabase();
return context.Shops
.Include(x => x.Pastries)
.ThenInclude(x => x.Pastry)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
public List<ShopViewModel> GetFilteredList(ShopSearchModel model)
{
if (string.IsNullOrEmpty(model.ShopName))
{
return new();
}
using var context = new ConfectioneryDatabase();
return context.Shops
.Include(x => x.Pastries)
.ThenInclude(x => x.Pastry)
.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 ConfectioneryDatabase();
return context.Shops
.Include(x => x.Pastries)
.ThenInclude(x => x.Pastry)
.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 ConfectioneryDatabase();
var newShop = Shop.Create(model, context);
if (newShop == null)
{
return null;
}
context.Shops.Add(newShop);
context.SaveChanges();
return newShop.GetViewModel;
}
public ShopViewModel? Update(ShopBindingModel model)
{
using var context = new ConfectioneryDatabase();
using var transaction = context.Database.BeginTransaction();
try
{
var product = context.Shops.FirstOrDefault(rec => rec.Id == model.Id);
if (product == null)
{
return null;
}
product.Update(model);
context.SaveChanges();
product.UpdatePastries(context, model);
transaction.Commit();
return product.GetViewModel;
}
catch
{
transaction.Rollback();
throw;
}
}
public ShopViewModel? Delete(ShopBindingModel model)
{
using var context = new ConfectioneryDatabase();
var element = context.Shops
.Include(x => x.Pastries)
.FirstOrDefault(rec => rec.Id == model.Id);
if (element != null)
{
context.Shops.Remove(element);
context.SaveChanges();
return element.GetViewModel;
}
return null;
}
public bool Supply(int pastryId, int count)
{
using ConfectioneryDatabase context = new ConfectioneryDatabase();
var transaction = context.Database.BeginTransaction();
foreach (Shop shop in context.Shops)
{
int freeShopSpace = shop.PastryCapacity - shop.ShopPastries.Select(y => y.Value.Item2).Sum();
if (freeShopSpace > 0)
{
if (freeShopSpace >= count)
{
if (shop.ShopPastries.ContainsKey(pastryId))
{
var shopPastry = shop.ShopPastries[pastryId];
shopPastry.Item2 += count;
shop.ShopPastries[pastryId] = shopPastry;
}
else
{
Pastry pastry = context.Pastrys.First(x => x.Id == pastryId);
shop.ShopPastries.Add(pastryId, (pastry, count));
}
shop.RemapPastries(context);
transaction.Commit();
return true;
}
else
{
int dif = count - freeShopSpace;
count -= freeShopSpace;
if (shop.ShopPastries.TryGetValue(pastryId, out var pastryCount))
{
var shopPastry = shop.ShopPastries[pastryId];
shopPastry.Item2 = pastryCount.Item2 + count;
shop.ShopPastries[pastryId] = shopPastry;
}
else
{
Pastry pastry = context.Pastrys.First(x => x.Id == pastryId);
shop.ShopPastries.Add(pastryId, (pastry, count));
}
shop.RemapPastries(context);
}
}
}
transaction.Rollback();
return false;
}
public bool Sell(int pastryId, int count)
{
using ConfectioneryDatabase context = new ConfectioneryDatabase();
var transaction = context.Database.BeginTransaction();
foreach (Shop shop in context.Shops)
{
int shopPastryCount = shop.ShopPastries.Select(x => x.Value).Where(x => x.Item1.Id == pastryId).Sum(x => x.Item2);
if (count - shopPastryCount >= 0)
{
count -= shopPastryCount;
shop.ShopPastries.Remove(pastryId);
}
else
{
var shopPastry = shop.ShopPastries[pastryId];
shopPastry.Item2 -= count;
count = 0;
shop.ShopPastries[pastryId] = shopPastry;
}
shop.RemapPastries(context);
if (count == 0)
{
transaction.Commit();
return true;
}
}
transaction.Rollback();
return false;
}
}
}

View File

@ -0,0 +1,246 @@
// <auto-generated />
using System;
using ConfectioneryDataBaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ConfectioneryDataBaseImplement.Migrations
{
[DbContext(typeof(ConfectioneryDatabase))]
[Migration("20230515043657_HardInitialCreate")]
partial class HardInitialCreate
{
/// <inheritdoc />
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("ConfectioneryDataBaseImplement.Models.Ingredient", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<double>("Cost")
.HasColumnType("float");
b.Property<string>("IngredientName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Ingredients");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<int>("PastryId")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<double>("Sum")
.HasColumnType("float");
b.HasKey("Id");
b.HasIndex("PastryId");
b.ToTable("Orders");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Pastry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("PastryName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Pastrys");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.PastryIngredient", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("IngredientId")
.HasColumnType("int");
b.Property<int>("PastryId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("IngredientId");
b.HasIndex("PastryId");
b.ToTable("PastryIngredients");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("OpeningDate")
.HasColumnType("datetime2");
b.Property<int>("PastryCapacity")
.HasColumnType("int");
b.Property<string>("ShopAdress")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ShopName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.ShopPastry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("PastryId")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PastryId");
b.HasIndex("ShopId");
b.ToTable("ShopPastries");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Order", b =>
{
b.HasOne("ConfectioneryDataBaseImplement.Models.Pastry", null)
.WithMany("Orders")
.HasForeignKey("PastryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.PastryIngredient", b =>
{
b.HasOne("ConfectioneryDataBaseImplement.Models.Ingredient", "Ingredient")
.WithMany("PastryIgredients")
.HasForeignKey("IngredientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ConfectioneryDataBaseImplement.Models.Pastry", "Pastry")
.WithMany("Ingredients")
.HasForeignKey("PastryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ingredient");
b.Navigation("Pastry");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.ShopPastry", b =>
{
b.HasOne("ConfectioneryDataBaseImplement.Models.Pastry", "Pastry")
.WithMany()
.HasForeignKey("PastryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ConfectioneryDataBaseImplement.Models.Shop", "Shop")
.WithMany("Pastries")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Pastry");
b.Navigation("Shop");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Ingredient", b =>
{
b.Navigation("PastryIgredients");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Pastry", b =>
{
b.Navigation("Ingredients");
b.Navigation("Orders");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Shop", b =>
{
b.Navigation("Pastries");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ConfectioneryDataBaseImplement.Migrations
{
/// <inheritdoc />
public partial class HardInitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Shops",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ShopName = table.Column<string>(type: "nvarchar(max)", nullable: false),
ShopAdress = table.Column<string>(type: "nvarchar(max)", nullable: false),
OpeningDate = table.Column<DateTime>(type: "datetime2", nullable: false),
PastryCapacity = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Shops", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ShopPastries",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ShopId = table.Column<int>(type: "int", nullable: false),
PastryId = table.Column<int>(type: "int", nullable: false),
Count = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ShopPastries", x => x.Id);
table.ForeignKey(
name: "FK_ShopPastries_Pastrys_PastryId",
column: x => x.PastryId,
principalTable: "Pastrys",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ShopPastries_Shops_ShopId",
column: x => x.ShopId,
principalTable: "Shops",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ShopPastries_PastryId",
table: "ShopPastries",
column: "PastryId");
migrationBuilder.CreateIndex(
name: "IX_ShopPastries_ShopId",
table: "ShopPastries",
column: "ShopId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ShopPastries");
migrationBuilder.DropTable(
name: "Shops");
}
}
}

View File

@ -121,6 +121,59 @@ namespace ConfectioneryDataBaseImplement.Migrations
b.ToTable("PastryIngredients"); b.ToTable("PastryIngredients");
}); });
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("OpeningDate")
.HasColumnType("datetime2");
b.Property<int>("PastryCapacity")
.HasColumnType("int");
b.Property<string>("ShopAdress")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("ShopName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.ShopPastry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("PastryId")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PastryId");
b.HasIndex("ShopId");
b.ToTable("ShopPastries");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Order", b => modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Order", b =>
{ {
b.HasOne("ConfectioneryDataBaseImplement.Models.Pastry", null) b.HasOne("ConfectioneryDataBaseImplement.Models.Pastry", null)
@ -149,6 +202,25 @@ namespace ConfectioneryDataBaseImplement.Migrations
b.Navigation("Pastry"); b.Navigation("Pastry");
}); });
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.ShopPastry", b =>
{
b.HasOne("ConfectioneryDataBaseImplement.Models.Pastry", "Pastry")
.WithMany()
.HasForeignKey("PastryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ConfectioneryDataBaseImplement.Models.Shop", "Shop")
.WithMany("Pastries")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Pastry");
b.Navigation("Shop");
});
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Ingredient", b => modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Ingredient", b =>
{ {
b.Navigation("PastryIgredients"); b.Navigation("PastryIgredients");
@ -160,6 +232,11 @@ namespace ConfectioneryDataBaseImplement.Migrations
b.Navigation("Orders"); b.Navigation("Orders");
}); });
modelBuilder.Entity("ConfectioneryDataBaseImplement.Models.Shop", b =>
{
b.Navigation("Pastries");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -0,0 +1,112 @@
using ConfectioneryContracts.BindingModels;
using ConfectioneryContracts.ViewModels;
using ConfectioneryDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConfectioneryDataBaseImplement.Models
{
public class Shop : IShopModel
{
public int Id { get; private set; }
[Required]
public string ShopName { get; private set; } = string.Empty;
[Required]
public string ShopAdress { get; private set; } = string.Empty;
[Required]
public DateTime OpeningDate { get; private set; }
[Required]
public int PastryCapacity { get; private set; }
private Dictionary<int, (IPastryModel, int)>? _shopPastries = null;
[NotMapped]
public Dictionary<int, (IPastryModel, int)> ShopPastries
{
get
{
if (_shopPastries == null)
{
_shopPastries = Pastries
.ToDictionary(recSP => recSP.PastryId, recPI => (recPI.Pastry as IPastryModel, recPI.Count));
}
return _shopPastries;
}
}
[ForeignKey("ShopId")]
public virtual List<ShopPastry> Pastries { get; set; } = new();
public static Shop Create(ShopBindingModel model, ConfectioneryDatabase context)
{
return new Shop()
{
Id = model.Id,
ShopAdress = model.ShopAdress,
ShopName = model.ShopName,
OpeningDate = model.OpeningDate,
PastryCapacity = model.PastryCapacity,
Pastries = model.ShopPastries.Select(x => new ShopPastry {
Pastry = context.Pastrys.First(y => y.Id == x.Key), Count = x.Value.Item2 }).ToList()
};
}
public void Update(ShopBindingModel? model)
{
if (model == null)
{
return;
}
ShopName = model.ShopName;
ShopAdress = model.ShopAdress;
OpeningDate = model.OpeningDate;
PastryCapacity = model.PastryCapacity;
}
public void UpdatePastries(ConfectioneryDatabase context, ShopBindingModel model)
{
var shopPastries = context.ShopPastries.Where(rec => rec.ShopId == model.Id).ToList();
if (shopPastries != null && shopPastries.Count > 0)
{
// удалили те, которых нет в модели
context.ShopPastries.RemoveRange(shopPastries.Where(rec => !model.ShopPastries.ContainsKey(rec.PastryId)));
context.SaveChanges();
// обновили количество у существующих записей
foreach (var updateIngredient in shopPastries)
{
updateIngredient.Count = model.ShopPastries[updateIngredient.PastryId].Item2;
model.ShopPastries.Remove(updateIngredient.PastryId);
}
var shop = context.Shops.First(x => x.Id == Id);
foreach (var sp in model.ShopPastries)
{
context.ShopPastries.Add(new ShopPastry
{
Shop = shop,
Pastry = context.Pastrys.First(x => x.Id == sp.Key),
Count = sp.Value.Item2
});
context.SaveChanges();
}
_shopPastries = null;
}
}
public ShopViewModel GetViewModel => new()
{
Id = Id,
ShopName = ShopName,
ShopAdress = ShopAdress,
ShopPastries = ShopPastries,
OpeningDate = OpeningDate,
PastryCapacity = PastryCapacity,
};
public void RemapPastries(ConfectioneryDatabase context)
{
UpdatePastries(context, new ShopBindingModel { Id = Id, ShopPastries = ShopPastries });
}
}
}

View File

@ -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 ConfectioneryDataBaseImplement.Models
{
public class ShopPastry
{
public int Id { get; set; }
[Required]
public int ShopId { get; set; }
[Required]
public int PastryId { get; set; }
[Required]
public int Count { get; set; }
public virtual Shop Shop { get; set; } = new();
public virtual Pastry Pastry { get; set; } = new();
}
}