Compare commits

..

2 Commits

Author SHA1 Message Date
67cf4fa5b4 4 лаба 2023-05-17 03:35:13 +04:00
c983d6aa31 норм вывод 2023-05-17 02:04:30 +04:00
23 changed files with 421 additions and 283 deletions

View File

@ -28,9 +28,7 @@
/// </summary>
private void InitializeComponent()
{
this.labelMaster = new System.Windows.Forms.Label();
this.labelSum = new System.Windows.Forms.Label();
this.comboBoxMaster = new System.Windows.Forms.ComboBox();
this.textBoxSum = new System.Windows.Forms.TextBox();
this.buttonSave = new System.Windows.Forms.Button();
this.buttonCancel = new System.Windows.Forms.Button();
@ -42,38 +40,18 @@
this.dateTimePicker = new System.Windows.Forms.DateTimePicker();
this.SuspendLayout();
//
// labelMaster
//
this.labelMaster.AutoSize = true;
this.labelMaster.Location = new System.Drawing.Point(12, 44);
this.labelMaster.Name = "labelMaster";
this.labelMaster.Size = new System.Drawing.Size(51, 15);
this.labelMaster.TabIndex = 0;
this.labelMaster.Text = "Мастер:";
//
// labelSum
//
this.labelSum.AutoSize = true;
this.labelSum.Location = new System.Drawing.Point(11, 102);
this.labelSum.Location = new System.Drawing.Point(11, 73);
this.labelSum.Name = "labelSum";
this.labelSum.Size = new System.Drawing.Size(48, 15);
this.labelSum.TabIndex = 2;
this.labelSum.Text = "Сумма:";
//
// comboBoxMaster
//
this.comboBoxMaster.BackColor = System.Drawing.SystemColors.Window;
this.comboBoxMaster.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxMaster.FormattingEnabled = true;
this.comboBoxMaster.Location = new System.Drawing.Point(93, 41);
this.comboBoxMaster.Name = "comboBoxMaster";
this.comboBoxMaster.Size = new System.Drawing.Size(238, 23);
this.comboBoxMaster.TabIndex = 3;
this.comboBoxMaster.SelectedIndexChanged += new System.EventHandler(this.ComboBoxMaster_SelectedIndexChanged);
//
// textBoxSum
//
this.textBoxSum.Location = new System.Drawing.Point(93, 99);
this.textBoxSum.Location = new System.Drawing.Point(93, 70);
this.textBoxSum.Name = "textBoxSum";
this.textBoxSum.ReadOnly = true;
this.textBoxSum.Size = new System.Drawing.Size(238, 23);
@ -81,7 +59,7 @@
//
// buttonSave
//
this.buttonSave.Location = new System.Drawing.Point(175, 170);
this.buttonSave.Location = new System.Drawing.Point(175, 141);
this.buttonSave.Name = "buttonSave";
this.buttonSave.Size = new System.Drawing.Size(75, 23);
this.buttonSave.TabIndex = 6;
@ -91,7 +69,7 @@
//
// buttonCancel
//
this.buttonCancel.Location = new System.Drawing.Point(256, 170);
this.buttonCancel.Location = new System.Drawing.Point(256, 141);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
this.buttonCancel.TabIndex = 7;
@ -124,7 +102,7 @@
this.comboBoxService.BackColor = System.Drawing.SystemColors.Window;
this.comboBoxService.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxService.FormattingEnabled = true;
this.comboBoxService.Location = new System.Drawing.Point(93, 70);
this.comboBoxService.Location = new System.Drawing.Point(93, 41);
this.comboBoxService.Name = "comboBoxService";
this.comboBoxService.Size = new System.Drawing.Size(238, 23);
this.comboBoxService.TabIndex = 11;
@ -133,7 +111,7 @@
// labelService
//
this.labelService.AutoSize = true;
this.labelService.Location = new System.Drawing.Point(11, 73);
this.labelService.Location = new System.Drawing.Point(11, 44);
this.labelService.Name = "labelService";
this.labelService.Size = new System.Drawing.Size(47, 15);
this.labelService.TabIndex = 10;
@ -142,7 +120,7 @@
// labelDate
//
this.labelDate.AutoSize = true;
this.labelDate.Location = new System.Drawing.Point(12, 134);
this.labelDate.Location = new System.Drawing.Point(12, 105);
this.labelDate.Name = "labelDate";
this.labelDate.Size = new System.Drawing.Size(35, 15);
this.labelDate.TabIndex = 12;
@ -150,7 +128,7 @@
//
// dateTimePicker
//
this.dateTimePicker.Location = new System.Drawing.Point(93, 128);
this.dateTimePicker.Location = new System.Drawing.Point(93, 99);
this.dateTimePicker.Name = "dateTimePicker";
this.dateTimePicker.Size = new System.Drawing.Size(238, 23);
this.dateTimePicker.TabIndex = 13;
@ -159,7 +137,7 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(346, 206);
this.ClientSize = new System.Drawing.Size(346, 177);
this.Controls.Add(this.dateTimePicker);
this.Controls.Add(this.labelDate);
this.Controls.Add(this.comboBoxService);
@ -169,9 +147,7 @@
this.Controls.Add(this.buttonCancel);
this.Controls.Add(this.buttonSave);
this.Controls.Add(this.textBoxSum);
this.Controls.Add(this.comboBoxMaster);
this.Controls.Add(this.labelSum);
this.Controls.Add(this.labelMaster);
this.Name = "FormCreateVisit";
this.Text = "Посещение";
this.Load += new System.EventHandler(this.FormCreateVisit_Load);
@ -181,10 +157,7 @@
}
#endregion
private Label labelMaster;
private Label labelSum;
private ComboBox comboBoxMaster;
private TextBox textBoxSum;
private Button buttonSave;
private Button buttonCancel;

View File

@ -10,16 +10,14 @@ namespace BeautySalon
private readonly ILogger _logger;
private readonly IServiceLogic _logicS;
private readonly IClientLogic _logicC;
private readonly IMasterLogic _logicM;
private readonly IVisitLogic _logicV;
public FormCreateVisit(ILogger<FormCreateVisit> logger, IVisitLogic logicV, IServiceLogic logicS, IClientLogic logicC, IMasterLogic logicM)
public FormCreateVisit(ILogger<FormCreateVisit> logger, IVisitLogic logicV, IServiceLogic logicS, IClientLogic logicC)
{
InitializeComponent();
_logger = logger;
_logicS = logicS;
_logicV = logicV;
_logicC = logicC;
_logicM = logicM;
LoadData();
}
@ -59,23 +57,6 @@ namespace BeautySalon
_logger.LogError(ex, "Ошибка загрузки списка клиентов");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
_logger.LogInformation("Загрузка мастеров для заказа");
try
{
var list = _logicM.ReadList(null);
if (list != null)
{
comboBoxMaster.DisplayMember = "MasterFIO";
comboBoxMaster.ValueMember = "Id";
comboBoxMaster.DataSource = list;
comboBoxMaster.SelectedItem = null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка загрузки списка мастеров");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void FormCreateVisit_Load(object sender, EventArgs e)
@ -86,7 +67,7 @@ namespace BeautySalon
private void CalcSum()
{
if (comboBoxService.SelectedValue != null)
if (comboBoxService.SelectedValue != null && comboBoxClient.SelectedValue != null)
{
try
{
@ -112,6 +93,23 @@ namespace BeautySalon
private void ComboBoxMaster_SelectedIndexChanged(object sender, EventArgs e)
{
_logger.LogInformation("Загрузка услуг для мастера");
try
{
var list = _logicS.ReadList(null);
if (list != null)
{
comboBoxService.DisplayMember = "ServiceName";
comboBoxService.ValueMember = "Id";
comboBoxService.DataSource = list;
comboBoxService.SelectedItem = null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка загрузки списка мастеров");
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ComboBoxService_SelectedIndexChanged(object sender, EventArgs e)
@ -131,23 +129,16 @@ namespace BeautySalon
MessageBox.Show("Выберите услугу", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (comboBoxMaster.SelectedValue == null)
{
MessageBox.Show("Выберите мастера", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
_logger.LogInformation("Создание посещения");
try
{
var operationResult = _logicV.Create(new VisitBindingModel
{
MasterId = Convert.ToInt32(comboBoxMaster.SelectedValue),
MasterFIO = comboBoxMaster.Text,
ClientId = Convert.ToInt32(comboBoxClient.SelectedValue),
ClientFIO = comboBoxClient.Text,
ServiceId = Convert.ToInt32(comboBoxService.SelectedValue),
ServiceName = comboBoxService.Text,
DateOfVisit = dateTimePicker.Value,
DateOfVisit = dateTimePicker.Value.ToUniversalTime(),
Sum = Convert.ToDouble(textBoxSum.Text)
});
if (!operationResult)

View File

@ -36,6 +36,7 @@
this.dataGridView = new System.Windows.Forms.DataGridView();
this.buttonCreateVisit = new System.Windows.Forms.Button();
this.buttonRef = new System.Windows.Forms.Button();
this.тестToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
this.SuspendLayout();
@ -43,7 +44,8 @@
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.справочникиToolStripMenuItem});
this.справочникиToolStripMenuItem,
this.тестToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(1078, 24);
@ -110,6 +112,13 @@
this.buttonRef.UseVisualStyleBackColor = true;
this.buttonRef.Click += new System.EventHandler(this.ButtonRef_Click);
//
// тестToolStripMenuItem
//
this.тестToolStripMenuItem.Name = естToolStripMenuItem";
this.тестToolStripMenuItem.Size = new System.Drawing.Size(42, 20);
this.тестToolStripMenuItem.Text = "Тест";
this.тестToolStripMenuItem.Click += new System.EventHandler(this.ТестToolStripMenuItem_Click);
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
@ -141,5 +150,6 @@
private DataGridView dataGridView;
private Button buttonCreateVisit;
private Button buttonRef;
private ToolStripMenuItem тестToolStripMenuItem;
}
}

View File

@ -72,8 +72,6 @@ namespace BeautySalon
dataGridView.DataSource = list;
dataGridView.Columns["ClientId"].Visible = false;
dataGridView.Columns["ClientFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridView.Columns["MasterId"].Visible = false;
dataGridView.Columns["MasterFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridView.Columns["ServiceId"].Visible = false;
dataGridView.Columns["ServiceName"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridView.Columns["DateOfVisit"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
@ -87,5 +85,14 @@ namespace BeautySalon
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ТестToolStripMenuItem_Click(object sender, EventArgs e)
{
var service = Program.ServiceProvider?.GetService(typeof(FormTests));
if (service is FormTests form)
{
form.ShowDialog();
}
}
}
}

View File

@ -28,12 +28,141 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.buttonInsertTest = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.textBoxInsertTime = new System.Windows.Forms.TextBox();
this.buttonReadTest = new System.Windows.Forms.Button();
this.textBoxReadTime = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.numericUpDownInsert = new System.Windows.Forms.NumericUpDown();
this.numericUpDownRead = new System.Windows.Forms.NumericUpDown();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownInsert)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownRead)).BeginInit();
this.SuspendLayout();
//
// buttonInsertTest
//
this.buttonInsertTest.Location = new System.Drawing.Point(12, 12);
this.buttonInsertTest.Name = "buttonInsertTest";
this.buttonInsertTest.Size = new System.Drawing.Size(86, 61);
this.buttonInsertTest.TabIndex = 0;
this.buttonInsertTest.Text = "Тест вставки";
this.buttonInsertTest.UseVisualStyleBackColor = true;
this.buttonInsertTest.Click += new System.EventHandler(this.ButtonInsertTest_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(104, 12);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(156, 15);
this.label1.TabIndex = 1;
this.label1.Text = "Введите кол-во элементов:";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(104, 53);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(146, 15);
this.label2.TabIndex = 3;
this.label2.Text = "Итоговое время запроса:";
//
// textBoxInsertTime
//
this.textBoxInsertTime.Location = new System.Drawing.Point(266, 50);
this.textBoxInsertTime.Name = "textBoxInsertTime";
this.textBoxInsertTime.ReadOnly = true;
this.textBoxInsertTime.Size = new System.Drawing.Size(100, 23);
this.textBoxInsertTime.TabIndex = 4;
//
// buttonReadTest
//
this.buttonReadTest.Location = new System.Drawing.Point(12, 106);
this.buttonReadTest.Name = "buttonReadTest";
this.buttonReadTest.Size = new System.Drawing.Size(86, 56);
this.buttonReadTest.TabIndex = 5;
this.buttonReadTest.Text = "Тест чтения";
this.buttonReadTest.UseVisualStyleBackColor = true;
this.buttonReadTest.Click += new System.EventHandler(this.ButtonReadTest_Click);
//
// textBoxReadTime
//
this.textBoxReadTime.Location = new System.Drawing.Point(266, 144);
this.textBoxReadTime.Name = "textBoxReadTime";
this.textBoxReadTime.ReadOnly = true;
this.textBoxReadTime.Size = new System.Drawing.Size(100, 23);
this.textBoxReadTime.TabIndex = 9;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(104, 147);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(146, 15);
this.label3.TabIndex = 8;
this.label3.Text = "Итоговое время запроса:";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(104, 106);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(156, 15);
this.label4.TabIndex = 6;
this.label4.Text = "Введите кол-во элементов:";
//
// numericUpDownInsert
//
this.numericUpDownInsert.Location = new System.Drawing.Point(266, 10);
this.numericUpDownInsert.Name = "numericUpDownInsert";
this.numericUpDownInsert.Size = new System.Drawing.Size(100, 23);
this.numericUpDownInsert.TabIndex = 10;
//
// numericUpDownRead
//
this.numericUpDownRead.Location = new System.Drawing.Point(266, 104);
this.numericUpDownRead.Name = "numericUpDownRead";
this.numericUpDownRead.Size = new System.Drawing.Size(100, 23);
this.numericUpDownRead.TabIndex = 11;
//
// FormTests
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "FormTests";
this.ClientSize = new System.Drawing.Size(383, 182);
this.Controls.Add(this.numericUpDownRead);
this.Controls.Add(this.numericUpDownInsert);
this.Controls.Add(this.textBoxReadTime);
this.Controls.Add(this.label3);
this.Controls.Add(this.label4);
this.Controls.Add(this.buttonReadTest);
this.Controls.Add(this.textBoxInsertTime);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.buttonInsertTest);
this.Name = "FormTests";
this.Text = "Тесты запросов к бд";
((System.ComponentModel.ISupportInitialize)(this.numericUpDownInsert)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownRead)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Button buttonInsertTest;
private Label label1;
private Label label2;
private TextBox textBoxInsertTime;
private Button buttonReadTest;
private TextBox textBoxReadTime;
private Label label3;
private Label label4;
private NumericUpDown numericUpDownInsert;
private NumericUpDown numericUpDownRead;
}
}

View File

@ -1,20 +1,45 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using BeautySalonContracts.BusinessLogicsContracts;
namespace BeautySalon
{
public partial class FormTests : Form
{
public FormTests()
private readonly IMasterLogic _masterLogic;
public FormTests(IMasterLogic masterLogic)
{
InitializeComponent();
_masterLogic = masterLogic;
numericUpDownInsert.Minimum = 1;
numericUpDownInsert.Maximum = 1000000;
numericUpDownRead.Minimum = 1;
numericUpDownRead.Maximum = 1000000;
}
private void ButtonInsertTest_Click(object sender, EventArgs e)
{
try
{
var result = _masterLogic.TestInsertList(Convert.ToInt32(numericUpDownInsert.Value));
textBoxInsertTime.Text = result;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ButtonReadTest_Click(object sender, EventArgs e)
{
try
{
var result = _masterLogic.TestReadList(Convert.ToInt32(numericUpDownRead.Value));
textBoxReadTime.Text = result;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}

View File

@ -1,64 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

View File

@ -48,6 +48,7 @@ namespace BeautySalon
services.AddTransient<FormClient>();
services.AddTransient<FormClients>();
services.AddTransient<FormMasterService>();
services.AddTransient<FormTests>();
}
}
}

View File

@ -4,6 +4,7 @@ using BeautySalonContracts.SearchModels;
using BeautySalonContracts.StoragesContracts;
using BeautySalonContracts.ViewModels;
using Microsoft.Extensions.Logging;
using System;
namespace BeautySalonBusinessLogic.BusinessLogics
{
@ -103,5 +104,15 @@ namespace BeautySalonBusinessLogic.BusinessLogics
throw new InvalidOperationException("Мастер с таким ФИО уже есть");
}
}
public string TestInsertList(int v)
{
return _masterStorage.TestInsertList(v);
}
public string TestReadList(int v)
{
return _masterStorage.TestReadList(v);
}
}
}

View File

@ -4,7 +4,6 @@
{
DateTime DateOfVisit { get; }
int ClientId { get; }
int MasterId { get; }
int ServiceId { get; }
double Sum { get; }
}

View File

@ -9,7 +9,7 @@ namespace BeautySalonDatabaseImplement
{
if (optionsBuilder.IsConfigured == false)
{
optionsBuilder.UseSqlServer(@"Data Source=DESKTOP-IHH1ICP\SQLEXPRESS;Initial Catalog=BeautySalonDatabaseFull;Integrated Security=True;MultipleActiveResultSets=True;;TrustServerCertificate=True");
optionsBuilder.UseNpgsql("Host=192.168.56.102;Port=5432;Database=BeautySalonDatabase;Username=postgres;Password=12345");
}
base.OnConfiguring(optionsBuilder);
}

View File

@ -13,6 +13,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
</ItemGroup>
<ItemGroup>

View File

@ -2,8 +2,12 @@
using BeautySalonContracts.SearchModels;
using BeautySalonContracts.StoragesContracts;
using BeautySalonContracts.ViewModels;
using BeautySalonDatabaseImplement;
using BeautySalonDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using System;
using BeautySalonDataModels.Models;
namespace BeautySalonDatabaseImplement.Implements
{
@ -68,17 +72,17 @@ namespace BeautySalonDatabaseImplement.Implements
using var transaction = context.Database.BeginTransaction();
try
{
var engine = context.Masters.FirstOrDefault(rec =>
var master = context.Masters.FirstOrDefault(rec =>
rec.Id == model.Id);
if (engine == null)
if (master == null)
{
return null;
}
engine.Update(model);
master.Update(model);
context.SaveChanges();
engine.UpdateServices(context, model);
master.UpdateServices(context, model);
transaction.Commit();
return engine.GetViewModel;
return master.GetViewModel;
}
catch
{
@ -100,5 +104,81 @@ namespace BeautySalonDatabaseImplement.Implements
}
return null;
}
public string TestInsertList(int v)
{
var context = new BeautySalonDatabase();
Stopwatch servicewatch = new();
Random rnd = new Random();
long[] res = new long[v * 2];
for (int i = 0; i < v; ++i)
{
int rndId = rnd.Next();
var model = new ServiceBindingModel
{
Id = rndId,
ServiceName = "Service" + rndId.ToString(),
Cost = rnd.Next(),
};
context.Services.Add(Service.Create(model));
servicewatch.Start();
context.SaveChanges();
servicewatch.Stop();
res[i] = servicewatch.ElapsedMilliseconds;
}
for (int i = 0; i < v; ++i)
{
int rndId = rnd.Next();
var model = new MasterBindingModel
{
Id = rndId,
MasterFIO = "Master" + rndId.ToString(),
Wage = rnd.Next(),
};
context.Masters.Add(Master.Create(context, model));
servicewatch.Start();
context.SaveChanges();
servicewatch.Stop();
res[i] = servicewatch.ElapsedMilliseconds;
}
long sum = 0;
for (int i = 0; i < v; i++)
{
sum += res[i];
}
int result = Convert.ToInt32(sum / v);
return result.ToString();
}
public string TestReadList(int v)
{
var context = new BeautySalonDatabase();
Stopwatch servicewatch = new();
long[] res = new long[v];
for (int i = 0; i < v; i++)
{
servicewatch.Start();
List<MasterViewModel> list = context.Masters
.Include(x => x.Services)
.ThenInclude(x => x.Service).ToList()
.Select(x => x.GetViewModel).ToList();
servicewatch.Stop();
res[i] = servicewatch.ElapsedMilliseconds;
}
long sum = 0;
for (int i = 0; i < v; i++)
{
sum += res[i];
}
int result = Convert.ToInt32(sum / v);
return result.ToString();
}
}
}

View File

@ -3,7 +3,6 @@ using BeautySalonContracts.SearchModels;
using BeautySalonContracts.StoragesContracts;
using BeautySalonContracts.ViewModels;
using BeautySalonDatabaseImplement.Models;
using System.ServiceModel;
namespace BeautySalonDatabaseImplement.Implements
{

View File

@ -13,7 +13,6 @@ namespace BeautySalonDatabaseImplement.Implements
{
using var context = new BeautySalonDatabase();
var element = context.Visits
.Include(x => x.Master)
.Include(x => x.Client)
.Include(x => x.Service)
.FirstOrDefault(rec => rec.Id == model.Id);
@ -55,7 +54,6 @@ namespace BeautySalonDatabaseImplement.Implements
using var context = new BeautySalonDatabase();
return context.Visits
.Include(x => x.Service)
.Include(x => x.Master)
.Include(x => x.Client)
.Select(x => x.GetViewModel).ToList();
}
@ -72,7 +70,6 @@ namespace BeautySalonDatabaseImplement.Implements
context.SaveChanges();
return context.Visits
.Include(x => x.Service)
.Include(x => x.Master)
.Include(x => x.Client)
.FirstOrDefault(x => x.Id == newVisit.Id)
?.GetViewModel;

View File

@ -3,16 +3,16 @@ using System;
using BeautySalonDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace BeautySalonDatabaseImplement.Migrations
{
[DbContext(typeof(BeautySalonDatabase))]
[Migration("20230513191649_InitialCreate")]
[Migration("20230516215849_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
@ -21,25 +21,25 @@ namespace BeautySalonDatabaseImplement.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
.HasAnnotation("Relational:MaxIdentifierLength", 63);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("BeautySalonDatabaseImplement.Models.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.HasKey("Id");
@ -50,16 +50,16 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("MasterFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<double>("Wage")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -70,18 +70,18 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("MasterId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<int>("ServiceId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<double>("Wage")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -96,19 +96,19 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("Cost")
.HasColumnType("float");
.HasColumnType("double precision");
b.Property<string>("ServiceName")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<double>("Time")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -119,36 +119,32 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<int>("ClientId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<DateTime>("DateOfVisit")
.HasColumnType("datetime2");
.HasColumnType("timestamp with time zone");
b.Property<string>("MasterFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("MasterId")
.HasColumnType("int");
b.Property<int?>("MasterId")
.HasColumnType("integer");
b.Property<int>("ServiceId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<string>("ServiceName")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<double>("Sum")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -188,11 +184,9 @@ namespace BeautySalonDatabaseImplement.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("BeautySalonDatabaseImplement.Models.Master", "Master")
b.HasOne("BeautySalonDatabaseImplement.Models.Master", null)
.WithMany("Visits")
.HasForeignKey("MasterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("MasterId");
b.HasOne("BeautySalonDatabaseImplement.Models.Service", "Service")
.WithMany()
@ -202,8 +196,6 @@ namespace BeautySalonDatabaseImplement.Migrations
b.Navigation("Client");
b.Navigation("Master");
b.Navigation("Service");
});

View File

@ -1,5 +1,6 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
@ -15,10 +16,10 @@ namespace BeautySalonDatabaseImplement.Migrations
name: "Clients",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ClientFIO = table.Column<string>(type: "nvarchar(max)", nullable: false),
PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: false)
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ClientFIO = table.Column<string>(type: "text", nullable: false),
PhoneNumber = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
@ -29,10 +30,10 @@ namespace BeautySalonDatabaseImplement.Migrations
name: "Masters",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
MasterFIO = table.Column<string>(type: "nvarchar(max)", nullable: false),
Wage = table.Column<double>(type: "float", nullable: false)
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
MasterFIO = table.Column<string>(type: "text", nullable: false),
Wage = table.Column<double>(type: "double precision", nullable: false)
},
constraints: table =>
{
@ -43,11 +44,11 @@ namespace BeautySalonDatabaseImplement.Migrations
name: "Services",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ServiceName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Cost = table.Column<double>(type: "float", nullable: false),
Time = table.Column<double>(type: "float", nullable: false)
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ServiceName = table.Column<string>(type: "text", nullable: false),
Cost = table.Column<double>(type: "double precision", nullable: false),
Time = table.Column<double>(type: "double precision", nullable: false)
},
constraints: table =>
{
@ -58,11 +59,11 @@ namespace BeautySalonDatabaseImplement.Migrations
name: "MasterServices",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
MasterId = table.Column<int>(type: "int", nullable: false),
ServiceId = table.Column<int>(type: "int", nullable: false),
Wage = table.Column<double>(type: "float", nullable: false)
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
MasterId = table.Column<int>(type: "integer", nullable: false),
ServiceId = table.Column<int>(type: "integer", nullable: false),
Wage = table.Column<double>(type: "double precision", nullable: false)
},
constraints: table =>
{
@ -85,16 +86,15 @@ namespace BeautySalonDatabaseImplement.Migrations
name: "Visits",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
DateOfVisit = table.Column<DateTime>(type: "datetime2", nullable: false),
ClientId = table.Column<int>(type: "int", nullable: false),
MasterId = table.Column<int>(type: "int", nullable: false),
ServiceId = table.Column<int>(type: "int", nullable: false),
ClientFIO = table.Column<string>(type: "nvarchar(max)", nullable: false),
MasterFIO = table.Column<string>(type: "nvarchar(max)", nullable: false),
ServiceName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Sum = table.Column<double>(type: "float", nullable: false)
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
DateOfVisit = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ClientId = table.Column<int>(type: "integer", nullable: false),
ServiceId = table.Column<int>(type: "integer", nullable: false),
ClientFIO = table.Column<string>(type: "text", nullable: false),
ServiceName = table.Column<string>(type: "text", nullable: false),
Sum = table.Column<double>(type: "double precision", nullable: false),
MasterId = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
@ -109,8 +109,7 @@ namespace BeautySalonDatabaseImplement.Migrations
name: "FK_Visits_Masters_MasterId",
column: x => x.MasterId,
principalTable: "Masters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
principalColumn: "Id");
table.ForeignKey(
name: "FK_Visits_Services_ServiceId",
column: x => x.ServiceId,

View File

@ -3,8 +3,8 @@ using System;
using BeautySalonDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
@ -18,25 +18,25 @@ namespace BeautySalonDatabaseImplement.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
.HasAnnotation("Relational:MaxIdentifierLength", 63);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("BeautySalonDatabaseImplement.Models.Client", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.HasKey("Id");
@ -47,16 +47,16 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("MasterFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<double>("Wage")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -67,18 +67,18 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("MasterId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<int>("ServiceId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<double>("Wage")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -93,19 +93,19 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<double>("Cost")
.HasColumnType("float");
.HasColumnType("double precision");
b.Property<string>("ServiceName")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<double>("Time")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -116,36 +116,32 @@ namespace BeautySalonDatabaseImplement.Migrations
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
.HasColumnType("integer");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClientFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<int>("ClientId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<DateTime>("DateOfVisit")
.HasColumnType("datetime2");
.HasColumnType("timestamp with time zone");
b.Property<string>("MasterFIO")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("MasterId")
.HasColumnType("int");
b.Property<int?>("MasterId")
.HasColumnType("integer");
b.Property<int>("ServiceId")
.HasColumnType("int");
.HasColumnType("integer");
b.Property<string>("ServiceName")
.IsRequired()
.HasColumnType("nvarchar(max)");
.HasColumnType("text");
b.Property<double>("Sum")
.HasColumnType("float");
.HasColumnType("double precision");
b.HasKey("Id");
@ -185,11 +181,9 @@ namespace BeautySalonDatabaseImplement.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("BeautySalonDatabaseImplement.Models.Master", "Master")
b.HasOne("BeautySalonDatabaseImplement.Models.Master", null)
.WithMany("Visits")
.HasForeignKey("MasterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("MasterId");
b.HasOne("BeautySalonDatabaseImplement.Models.Service", "Service")
.WithMany()
@ -199,8 +193,6 @@ namespace BeautySalonDatabaseImplement.Migrations
b.Navigation("Client");
b.Navigation("Master");
b.Navigation("Service");
});

View File

@ -11,15 +11,12 @@ namespace BeautySalonDatabaseImplement.Models
[Required]
public DateTime DateOfVisit { get; private set; }
public int ClientId { get; private set; }
public int MasterId { get; private set; }
public int ServiceId { get; private set; }
public string ClientFIO { get; set; } = string.Empty;
public string MasterFIO { get; set; } = string.Empty;
public string ServiceName { get; set; } = string.Empty;
[Required]
public double Sum { get; private set; }
public Client Client { get; set; }
public virtual Master Master { get; set; }
public virtual Service Service { get; set; }
public static Visit? Create(VisitBindingModel? model)
@ -34,8 +31,6 @@ namespace BeautySalonDatabaseImplement.Models
Id = model.Id,
ClientId = model.ClientId,
ClientFIO = model.ClientFIO,
MasterId = model.MasterId,
MasterFIO = model.MasterFIO,
ServiceId = model.ServiceId,
ServiceName = model.ServiceName,
Sum = model.Sum,
@ -64,8 +59,6 @@ namespace BeautySalonDatabaseImplement.Models
Id = Id,
ClientId = ClientId,
ClientFIO = context.Clients.FirstOrDefault(x => x.Id == ClientId)?.ClientFIO ?? string.Empty,
MasterId = MasterId,
MasterFIO = context.Masters.FirstOrDefault(x => x.Id == MasterId)?.MasterFIO ?? string.Empty,
ServiceId = ServiceId,
ServiceName = context.Services.FirstOrDefault(x => x.Id == ServiceId)?.ServiceName ?? string.Empty,
Sum = Sum,

View File

@ -7,10 +7,8 @@ namespace BeautySalonContracts.BindingModels
public int Id { get; set; }
public DateTime DateOfVisit { get; set; }
public int ClientId { get; set; }
public int MasterId { get; set; }
public int ServiceId { get; set; }
public string ClientFIO { get; set; } = string.Empty;
public string MasterFIO { get; set; } = string.Empty;
public string ServiceName { get; set; } = string.Empty;
public double Sum { get; set; }
}

View File

@ -11,5 +11,7 @@ namespace BeautySalonContracts.BusinessLogicsContracts
bool Create(MasterBindingModel model);
bool Update(MasterBindingModel model);
bool Delete(MasterBindingModel model);
string TestInsertList(int v);
string TestReadList(int v);
}
}

View File

@ -12,5 +12,7 @@ namespace BeautySalonContracts.StoragesContracts
MasterViewModel? Insert(MasterBindingModel model);
MasterViewModel? Update(MasterBindingModel model);
MasterViewModel? Delete(MasterBindingModel model);
string TestInsertList(int v);
string TestReadList(int v);
}
}

View File

@ -11,9 +11,6 @@ namespace BeautySalonContracts.ViewModels
public int ClientId { get; set; }
[DisplayName("Клиент")]
public string ClientFIO { get; set; } = string.Empty;
public int MasterId { get; set; }
[DisplayName("Мастер")]
public string MasterFIO { get; set; } = string.Empty;
public int ServiceId { get; set; }
[DisplayName("Услуга")]
public string ServiceName { get; set; } = string.Empty;