diff --git a/ComputersShop/ComputersShopBusinessLogic/ClientLogic.cs b/ComputersShop/ComputersShopBusinessLogic/ClientLogic.cs new file mode 100644 index 0000000..fc040cf --- /dev/null +++ b/ComputersShop/ComputersShopBusinessLogic/ClientLogic.cs @@ -0,0 +1,111 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.BusinessLogicsContracts; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.StoragesContracts; +using ComputersShopContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace ComputersShopBusinessLogic +{ + public class ClientLogic : IClientLogic + { + private readonly ILogger _logger; + private readonly IClientStorage _clientStorage; + public ClientLogic(ILogger logger, IClientStorage clientStorage) + { + _logger = logger; + _clientStorage = clientStorage; + } + public List? ReadList(ClientSearchModel? model) + { + _logger.LogInformation("ReadList. ClientName:{ClientName}.Id:{ Id}", model?.ClientFIO, model?.Id); + var list = model == null ? _clientStorage.GetFullList() : _clientStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + public ClientViewModel? ReadElement(ClientSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. ClientFIO:{ClientFIO}.Id:{ Id}", model.ClientFIO, model.Id); + var element = _clientStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + return element; + } + public bool Create(ClientBindingModel model) + { + CheckModel(model); + if (_clientStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(ClientBindingModel model) + { + CheckModel(model); + if (_clientStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + public bool Delete(ClientBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_clientStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + private void CheckModel(ClientBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.ClientFIO)) + { + throw new ArgumentNullException("Не заполнено имя", nameof(model.ClientFIO)); + } + if (string.IsNullOrEmpty(model.Email)) + { + throw new ArgumentNullException("Не заполнен email", nameof(model.Email)); + } + if (string.IsNullOrEmpty(model.Password)) + { + throw new ArgumentNullException("Не заполнен пароль", nameof(model.Password)); + } + _logger.LogInformation("Client. ClientName:{ClientName}.Id: {Id} ", model.ClientFIO, model.Id); + var element = _clientStorage.GetElement(new ClientSearchModel + { + ClientFIO = model.ClientFIO + }); + if (element != null && element.Id != model.Id) + { + throw new InvalidOperationException("Компонент с таким названием уже есть"); + } + } + } +} diff --git a/ComputersShop/ComputersShopContracts/BindingModels/ClientBindingModel.cs b/ComputersShop/ComputersShopContracts/BindingModels/ClientBindingModel.cs new file mode 100644 index 0000000..5ea6793 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/BindingModels/ClientBindingModel.cs @@ -0,0 +1,12 @@ +using ComputersShopDataModels.Models; + +namespace ComputersShopContracts.BindingModels +{ + public class ClientBindingModel : IClientModel + { + public int Id { get; set; } + public string ClientFIO { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + } +} diff --git a/ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IClientLogic.cs b/ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IClientLogic.cs new file mode 100644 index 0000000..7a81597 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/BusinessLogicsContracts/IClientLogic.cs @@ -0,0 +1,15 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.ViewModels; + +namespace ComputersShopContracts.BusinessLogicsContracts +{ + public interface IClientLogic + { + List? ReadList(ClientSearchModel? model); + ClientViewModel? ReadElement(ClientSearchModel model); + bool Create(ClientBindingModel model); + bool Update(ClientBindingModel model); + bool Delete(ClientBindingModel model); + } +} diff --git a/ComputersShop/ComputersShopContracts/SearchModels/ClientSearchModel.cs b/ComputersShop/ComputersShopContracts/SearchModels/ClientSearchModel.cs new file mode 100644 index 0000000..beb3f1c --- /dev/null +++ b/ComputersShop/ComputersShopContracts/SearchModels/ClientSearchModel.cs @@ -0,0 +1,10 @@ +namespace ComputersShopContracts.SearchModels +{ + public class ClientSearchModel + { + public int? Id { get; set; } + public string? ClientFIO { get; set; } + public string? Email { get; set; } + public string? Password { get; set; } + } +} diff --git a/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs b/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs new file mode 100644 index 0000000..7e779c3 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/StoragesContracts/IClientStorage.cs @@ -0,0 +1,16 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.ViewModels; + +namespace ComputersShopContracts.StoragesContracts +{ + public interface IClientStorage + { + List GetFullList(); + List GetFilteredList(ClientSearchModel model); + ClientViewModel? GetElement(ClientSearchModel model); + ClientViewModel? Insert(ClientBindingModel model); + ClientViewModel? Update(ClientBindingModel model); + ClientViewModel? Delete(ClientBindingModel model); + } +} diff --git a/ComputersShop/ComputersShopContracts/ViewModels/ClientViewModel.cs b/ComputersShop/ComputersShopContracts/ViewModels/ClientViewModel.cs new file mode 100644 index 0000000..481b429 --- /dev/null +++ b/ComputersShop/ComputersShopContracts/ViewModels/ClientViewModel.cs @@ -0,0 +1,19 @@ +using ComputersShopDataModels.Models; +using System.ComponentModel; + +namespace ComputersShopContracts.ViewModels +{ + public class ClientViewModel : IClientModel + { + public int Id { get; set; } + + [DisplayName("ФИО клиента")] + public string ClientFIO { get; set; } = string.Empty; + + [DisplayName("Логин {эл. почта}")] + public string Email { get; set; } = string.Empty; + + [DisplayName("Пароль")] + public string Password { get; set; } = string.Empty; + } +} diff --git a/ComputersShop/ComputersShopDataModels/Models/IClientModel.cs b/ComputersShop/ComputersShopDataModels/Models/IClientModel.cs new file mode 100644 index 0000000..3ce4bb0 --- /dev/null +++ b/ComputersShop/ComputersShopDataModels/Models/IClientModel.cs @@ -0,0 +1,9 @@ +namespace ComputersShopDataModels.Models +{ + public interface IClientModel : IId + { + string ClientFIO { get; } + string Email { get; } + string Password { get; } + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/ComputersShopDatabase.cs b/ComputersShop/ComputersShopDatabaseImplement/ComputersShopDatabase.cs index aad2b7f..9417ccf 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/ComputersShopDatabase.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/ComputersShopDatabase.cs @@ -25,5 +25,6 @@ namespace ComputersShopDatabaseImplement public virtual DbSet Computers { set; get; } public virtual DbSet ComputerComponents { set; get; } public virtual DbSet Orders { set; get; } + public virtual DbSet Clients { set; get; } } } diff --git a/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs b/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs new file mode 100644 index 0000000..7f9d187 --- /dev/null +++ b/ComputersShop/ComputersShopDatabaseImplement/Implements/ClientStorage.cs @@ -0,0 +1,82 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.SearchModels; +using ComputersShopContracts.StoragesContracts; +using ComputersShopContracts.ViewModels; +using ComputersShopDatabaseImplement.Models; + +namespace ComputersShopDatabaseImplement.Implements +{ + public class ClientStorage : IClientStorage + { + public List GetFullList() + { + using var context = new ComputersShopDatabase(); + return context.Clients.Select(x => x.GetViewModel).ToList(); + } + public List GetFilteredList(ClientSearchModel model) + { + if (string.IsNullOrEmpty(model.Email)) + { + return new(); + } + using var context = new ComputersShopDatabase(); + return context.Clients + .Where(x => x.Email.Contains(model.Email)) + .Select(x => x.GetViewModel) + .ToList(); + } + public ClientViewModel? GetElement(ClientSearchModel model) + { + using var context = new ComputersShopDatabase(); + if (model.Id.HasValue)//сначала ищем по Id + { + return context.Clients.FirstOrDefault(x => x.Id == model.Id)?.GetViewModel; + } + else if (!string.IsNullOrEmpty(model.Email) && string.IsNullOrEmpty(model.Password))//затем по логину + { + return context.Clients.FirstOrDefault(x => x.Email == model.Email)?.GetViewModel; + } + else if (!string.IsNullOrEmpty(model.Email) && !string.IsNullOrEmpty(model.Password))//затем по логину и паролю + { + return context.Clients.FirstOrDefault(x => x.Email == model.Email && x.Password == model.Password)?.GetViewModel; + } + return null; + } + public ClientViewModel? Insert(ClientBindingModel model) + { + using var context = new ComputersShopDatabase(); + var newClient = Client.Create(model); + if (newClient == null) + { + return null; + } + context.Clients.Add(newClient); + context.SaveChanges(); + return newClient.GetViewModel; + } + public ClientViewModel? Update(ClientBindingModel model) + { + using var context = new ComputersShopDatabase(); + var client = context.Clients.FirstOrDefault(x => x.Id == model.Id); + if (client == null) + { + return null; + } + client.Update(model); + context.SaveChanges(); + return client.GetViewModel; + } + public ClientViewModel? Delete(ClientBindingModel model) + { + using var context = new ComputersShopDatabase(); + var element = context.Clients.FirstOrDefault(x => x.Id == model.Id); + if (element == null) + { + return null; + } + context.Clients.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/Migrations/20230426042353_addClient.Designer.cs b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20230426042353_addClient.Designer.cs new file mode 100644 index 0000000..1a32422 --- /dev/null +++ b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20230426042353_addClient.Designer.cs @@ -0,0 +1,212 @@ +// +using System; +using ComputersShopDatabaseImplement; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ComputersShopDatabaseImplement.Migrations +{ + [DbContext(typeof(ComputersShopDatabase))] + [Migration("20230426042353_addClient")] + partial class addClient + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClientFIO") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Clients"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Component", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ComponentName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Cost") + .HasColumnType("float"); + + b.HasKey("Id"); + + b.ToTable("Components"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Computer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ComputerName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Price") + .HasColumnType("float"); + + b.HasKey("Id"); + + b.ToTable("Computers"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.ComputerComponent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ComponentId") + .HasColumnType("int"); + + b.Property("ComputerId") + .HasColumnType("int"); + + b.Property("Count") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ComponentId"); + + b.HasIndex("ComputerId"); + + b.ToTable("ComputerComponents"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("ComputerId") + .HasColumnType("int"); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("DateCreate") + .HasColumnType("datetime2"); + + b.Property("DateImplement") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Sum") + .HasColumnType("float"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("ComputerId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.ComputerComponent", b => + { + b.HasOne("ComputersShopDatabaseImplement.Models.Component", "Component") + .WithMany("ComputerComponents") + .HasForeignKey("ComponentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ComputersShopDatabaseImplement.Models.Computer", "Computer") + .WithMany("Components") + .HasForeignKey("ComputerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Component"); + + b.Navigation("Computer"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => + { + b.HasOne("ComputersShopDatabaseImplement.Models.Client", "Client") + .WithMany("Orders") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ComputersShopDatabaseImplement.Models.Computer", null) + .WithMany("Orders") + .HasForeignKey("ComputerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Client", b => + { + b.Navigation("Orders"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Component", b => + { + b.Navigation("ComputerComponents"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Computer", b => + { + b.Navigation("Components"); + + b.Navigation("Orders"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/Migrations/20230426042353_addClient.cs b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20230426042353_addClient.cs new file mode 100644 index 0000000..84a70f9 --- /dev/null +++ b/ComputersShop/ComputersShopDatabaseImplement/Migrations/20230426042353_addClient.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ComputersShopDatabaseImplement.Migrations +{ + /// + public partial class addClient : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ClientId", + table: "Orders", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "Clients", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ClientFIO = table.Column(type: "nvarchar(max)", nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: false), + Password = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Clients", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_ClientId", + table: "Orders", + column: "ClientId"); + + migrationBuilder.AddForeignKey( + name: "FK_Orders_Clients_ClientId", + table: "Orders", + column: "ClientId", + principalTable: "Clients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Orders_Clients_ClientId", + table: "Orders"); + + migrationBuilder.DropTable( + name: "Clients"); + + migrationBuilder.DropIndex( + name: "IX_Orders_ClientId", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "ClientId", + table: "Orders"); + } + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs b/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs index be50f51..27e603c 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Migrations/ComputersShopDatabaseModelSnapshot.cs @@ -22,6 +22,31 @@ namespace ComputersShopDatabaseImplement.Migrations SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClientFIO") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Clients"); + }); + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Component", b => { b.Property("Id") @@ -96,6 +121,9 @@ namespace ComputersShopDatabaseImplement.Migrations SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + b.Property("ClientId") + .HasColumnType("int"); + b.Property("ComputerId") .HasColumnType("int"); @@ -116,6 +144,8 @@ namespace ComputersShopDatabaseImplement.Migrations b.HasKey("Id"); + b.HasIndex("ClientId"); + b.HasIndex("ComputerId"); b.ToTable("Orders"); @@ -142,11 +172,24 @@ namespace ComputersShopDatabaseImplement.Migrations modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Order", b => { + b.HasOne("ComputersShopDatabaseImplement.Models.Client", "Client") + .WithMany("Orders") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("ComputersShopDatabaseImplement.Models.Computer", null) .WithMany("Orders") .HasForeignKey("ComputerId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Client", b => + { + b.Navigation("Orders"); }); modelBuilder.Entity("ComputersShopDatabaseImplement.Models.Component", b => diff --git a/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs b/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs new file mode 100644 index 0000000..5f5ad6c --- /dev/null +++ b/ComputersShop/ComputersShopDatabaseImplement/Models/Client.cs @@ -0,0 +1,52 @@ +using ComputersShopContracts.BindingModels; +using ComputersShopContracts.ViewModels; +using ComputersShopDataModels.Models; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; + +namespace ComputersShopDatabaseImplement.Models +{ + public class Client : IClientModel + { + public int Id { get; private set; } + [Required] + public string ClientFIO { get; private set; } = string.Empty; + [Required] + public string Email { get; private set; } = string.Empty; + [Required] + public string Password { get; private set; } = string.Empty; + [ForeignKey("ClientId")] + public virtual List Orders { get; set; } = new(); + public static Client? Create(ClientBindingModel model) + { + if (model == null) + { + return null; + } + return new() + { + Id = model.Id, + ClientFIO = model.ClientFIO, + Email = model.Email, + Password = model.Password + }; + } + public void Update(ClientBindingModel model) + { + if (model == null) + { + return; + } + ClientFIO = model.ClientFIO; + Email = model.Email; + Password = model.Password; + } + public ClientViewModel GetViewModel => new() + { + Id = Id, + ClientFIO = ClientFIO, + Email = Email, + Password = Password, + }; + } +} diff --git a/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs b/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs index b600817..af8f334 100644 --- a/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs +++ b/ComputersShop/ComputersShopDatabaseImplement/Models/Order.cs @@ -20,6 +20,9 @@ namespace ComputersShopDatabaseImplement.Models [Required] public DateTime DateCreate { get; private set; } = DateTime.Now; public DateTime? DateImplement { get; private set; } + [Required] + public int ClientId { get; private set; } + public virtual Client? Client { get; set; } public static Order? Create(OrderBindingModel model) {