| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- using Microsoft.Data.SqlClient;
- using System.Data;
- namespace TradeApp.WinForms.V08;
- public sealed class DatabaseClient : IDisposable
- {
- private readonly string _connectionString;
- public DatabaseClient(string connectionString)
- {
- _connectionString = connectionString;
- }
- public void Dispose()
- {
- }
- public AppUser? Authenticate(string login, string password)
- {
- using var connection = Open();
- using var command = new SqlCommand(@"
- SELECT TOP (1) u.UserId, u.FullName, r.Name
- FROM dbo.Users u
- JOIN dbo.Roles r ON r.RoleId = u.RoleId
- WHERE u.Login = @login
- AND u.PasswordHash = HASHBYTES('SHA2_256', CONVERT(NVARCHAR(4000), @password));", connection);
- command.Parameters.Add("@login", SqlDbType.NVarChar, 255).Value = login;
- command.Parameters.Add("@password", SqlDbType.NVarChar, 4000).Value = password;
- using var reader = command.ExecuteReader();
- return reader.Read()
- ? new AppUser(reader.GetInt32(0), reader.GetString(1), reader.GetString(2))
- : null;
- }
- public List<ProductView> LoadProducts(string search, string searchField, string supplier, string sortMode)
- {
- var searchExpression = searchField switch
- {
- "Артикул" => "p.Article",
- "Наименование" => "p.Name",
- "Категория" => "c.Name",
- "Описание" => "p.Description",
- "Производитель" => "m.Name",
- "Поставщик" => "s.Name",
- "Единица измерения" => "u.Name",
- "Цена" => "CONVERT(NVARCHAR(50), p.Price)",
- "Скидка" => "CONVERT(NVARCHAR(50), p.DiscountPercent)",
- "Цена со скидкой" => "CONVERT(NVARCHAR(50), ROUND(p.Price * (100 - p.DiscountPercent) / 100, 2))",
- "Количество на складе" => "CONVERT(NVARCHAR(50), p.StockQuantity)",
- _ => "CONCAT(p.Article, N' ', p.Name, N' ', c.Name, N' ', p.Description, N' ', m.Name, N' ', s.Name, N' ', u.Name, N' ', p.Price, N' ', p.DiscountPercent, N' ', p.StockQuantity)"
- };
- var orderBy = sortMode switch
- {
- "Цена по убыванию" => "p.Price DESC",
- "Цена по возрастанию" => "p.Price ASC",
- "Остаток по убыванию" => "p.StockQuantity DESC",
- "Остаток по возрастанию" => "p.StockQuantity ASC",
- _ => "p.Name ASC"
- };
- using var connection = Open();
- using var command = new SqlCommand($@"
- SELECT p.ProductId, p.Article, p.Name, c.Name, ISNULL(p.Description, N''),
- m.Name, s.Name, p.Price, p.DiscountPercent, u.Name, p.StockQuantity, p.ImagePath
- FROM dbo.Products p
- JOIN dbo.Categories c ON c.CategoryId = p.CategoryId
- JOIN dbo.Manufacturers m ON m.ManufacturerId = p.ManufacturerId
- JOIN dbo.Suppliers s ON s.SupplierId = p.SupplierId
- JOIN dbo.Units u ON u.UnitId = p.UnitId
- WHERE (@supplier = N'' OR s.Name = @supplier)
- AND (@search = N'' OR {searchExpression} LIKE N'%' + @search + N'%')
- ORDER BY {orderBy};", connection);
- command.Parameters.Add("@search", SqlDbType.NVarChar, 1000).Value = search;
- command.Parameters.Add("@supplier", SqlDbType.NVarChar, 200).Value = supplier == "Все поставщики" ? "" : supplier;
- var result = new List<ProductView>();
- using var reader = command.ExecuteReader();
- while (reader.Read())
- {
- result.Add(new ProductView
- {
- ProductId = reader.GetInt32(0),
- Article = reader.GetString(1),
- Name = reader.GetString(2),
- Category = reader.GetString(3),
- Description = reader.GetString(4),
- Manufacturer = reader.GetString(5),
- Supplier = reader.GetString(6),
- Price = reader.GetDecimal(7),
- DiscountPercent = reader.GetDecimal(8),
- Unit = reader.GetString(9),
- StockQuantity = reader.GetInt32(10),
- ImagePath = reader.GetString(11)
- });
- }
- return result;
- }
- public List<string> LoadSuppliers() => LoadDictionary("dbo.Suppliers");
- public List<string> LoadCategories() => LoadDictionary("dbo.Categories");
- public List<string> LoadManufacturers() => LoadDictionary("dbo.Manufacturers");
- public List<string> LoadUnits() => LoadDictionary("dbo.Units");
- public List<string> LoadStatuses() => LoadDictionary("dbo.OrderStatuses");
- public List<string> LoadProductArticles()
- {
- using var connection = Open();
- using var command = new SqlCommand("SELECT Article FROM dbo.Products ORDER BY Article;", connection);
- using var reader = command.ExecuteReader();
- var result = new List<string>();
- while (reader.Read())
- {
- result.Add(reader.GetString(0));
- }
- return result;
- }
- public Dictionary<int, string> LoadPickupPoints()
- {
- using var connection = Open();
- using var command = new SqlCommand("SELECT PickupPointId, Address FROM dbo.PickupPoints ORDER BY PickupPointId;", connection);
- using var reader = command.ExecuteReader();
- var result = new Dictionary<int, string>();
- while (reader.Read())
- {
- result[reader.GetInt32(0)] = reader.GetString(1);
- }
- return result;
- }
- public void SaveProduct(ProductView product)
- {
- using var connection = Open();
- using var transaction = connection.BeginTransaction();
- var unitId = EnsureDictionaryValue(connection, transaction, "dbo.Units", "UnitId", product.Unit);
- var supplierId = EnsureDictionaryValue(connection, transaction, "dbo.Suppliers", "SupplierId", product.Supplier);
- var manufacturerId = EnsureDictionaryValue(connection, transaction, "dbo.Manufacturers", "ManufacturerId", product.Manufacturer);
- var categoryId = EnsureDictionaryValue(connection, transaction, "dbo.Categories", "CategoryId", product.Category);
- using var command = new SqlCommand(product.ProductId == 0 ? @"
- INSERT INTO dbo.Products (Article, Name, UnitId, Price, SupplierId, ManufacturerId, CategoryId, DiscountPercent, StockQuantity, Description, ImagePath)
- VALUES (@article, @name, @unitId, @price, @supplierId, @manufacturerId, @categoryId, @discount, @stock, @description, @image);" : @"
- UPDATE dbo.Products
- SET Article=@article, Name=@name, UnitId=@unitId, Price=@price, SupplierId=@supplierId,
- ManufacturerId=@manufacturerId, CategoryId=@categoryId, DiscountPercent=@discount,
- StockQuantity=@stock, Description=@description, ImagePath=@image
- WHERE ProductId=@productId;", connection, transaction);
- command.Parameters.Add("@productId", SqlDbType.Int).Value = product.ProductId;
- command.Parameters.Add("@article", SqlDbType.NVarChar, 50).Value = product.Article;
- command.Parameters.Add("@name", SqlDbType.NVarChar, 1000).Value = product.Name;
- command.Parameters.Add("@unitId", SqlDbType.Int).Value = unitId;
- AddDecimal(command, "@price", product.Price);
- command.Parameters.Add("@supplierId", SqlDbType.Int).Value = supplierId;
- command.Parameters.Add("@manufacturerId", SqlDbType.Int).Value = manufacturerId;
- command.Parameters.Add("@categoryId", SqlDbType.Int).Value = categoryId;
- AddDecimal(command, "@discount", product.DiscountPercent);
- command.Parameters.Add("@stock", SqlDbType.Int).Value = product.StockQuantity;
- command.Parameters.Add("@description", SqlDbType.NVarChar).Value = string.IsNullOrWhiteSpace(product.Description) ? DBNull.Value : product.Description;
- command.Parameters.Add("@image", SqlDbType.NVarChar, 260).Value = string.IsNullOrWhiteSpace(product.ImagePath) ? "picture.png" : product.ImagePath;
- command.ExecuteNonQuery();
- transaction.Commit();
- }
- public bool ProductIsUsedInOrders(int productId)
- {
- using var connection = Open();
- using var command = new SqlCommand("SELECT COUNT(*) FROM dbo.OrderItems WHERE ProductId=@id;", connection);
- command.Parameters.Add("@id", SqlDbType.Int).Value = productId;
- return Convert.ToInt32(command.ExecuteScalar()) > 0;
- }
- public bool ProductImageIsUsed(string imagePath, int exceptProductId)
- {
- if (string.IsNullOrWhiteSpace(imagePath) ||
- imagePath.Equals("picture.png", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- using var connection = Open();
- using var command = new SqlCommand(@"
- SELECT COUNT(*)
- FROM dbo.Products
- WHERE ImagePath=@imagePath AND ProductId<>@productId;", connection);
- command.Parameters.Add("@imagePath", SqlDbType.NVarChar, 260).Value = imagePath;
- command.Parameters.Add("@productId", SqlDbType.Int).Value = exceptProductId;
- return Convert.ToInt32(command.ExecuteScalar()) > 0;
- }
- public void DeleteProduct(int productId)
- {
- using var connection = Open();
- using var command = new SqlCommand("DELETE FROM dbo.Products WHERE ProductId=@id;", connection);
- command.Parameters.Add("@id", SqlDbType.Int).Value = productId;
- command.ExecuteNonQuery();
- }
- public List<OrderView> LoadOrders()
- {
- using var connection = Open();
- using var command = new SqlCommand(@"
- SELECT o.OrderId, ISNULL(u.FullName, N''), pp.Address, os.Name, o.OrderDate, o.DeliveryDate, o.ReceiveCode,
- STRING_AGG(CONCAT(p.Article, N' x', oi.Quantity), N', ')
- FROM dbo.Orders o
- LEFT JOIN dbo.Users u ON u.UserId = o.UserId
- JOIN dbo.PickupPoints pp ON pp.PickupPointId = o.PickupPointId
- JOIN dbo.OrderStatuses os ON os.OrderStatusId = o.OrderStatusId
- LEFT JOIN dbo.OrderItems oi ON oi.OrderId = o.OrderId
- LEFT JOIN dbo.Products p ON p.ProductId = oi.ProductId
- GROUP BY o.OrderId, u.FullName, pp.Address, os.Name, o.OrderDate, o.DeliveryDate, o.ReceiveCode
- ORDER BY o.OrderId DESC;", connection);
- var result = new List<OrderView>();
- using var reader = command.ExecuteReader();
- while (reader.Read())
- {
- result.Add(new OrderView
- {
- OrderId = reader.GetInt32(0),
- Customer = reader.GetString(1),
- PickupPoint = reader.GetString(2),
- Status = reader.GetString(3),
- OrderDate = reader.IsDBNull(4) ? null : reader.GetDateTime(4),
- DeliveryDate = reader.IsDBNull(5) ? null : reader.GetDateTime(5),
- ReceiveCode = reader.GetString(6),
- Articles = reader.IsDBNull(7) ? "" : reader.GetString(7)
- });
- }
- return result;
- }
- public void DeleteOrder(int orderId)
- {
- using var connection = Open();
- using var command = new SqlCommand("DELETE FROM dbo.Orders WHERE OrderId=@id;", connection);
- command.Parameters.Add("@id", SqlDbType.Int).Value = orderId;
- command.ExecuteNonQuery();
- }
- public (string Article, int Quantity)? LoadFirstOrderItem(int orderId)
- {
- using var connection = Open();
- using var command = new SqlCommand(@"
- SELECT TOP (1) p.Article, oi.Quantity
- FROM dbo.OrderItems oi
- JOIN dbo.Products p ON p.ProductId = oi.ProductId
- WHERE oi.OrderId=@orderId
- ORDER BY oi.OrderItemId;", connection);
- command.Parameters.Add("@orderId", SqlDbType.Int).Value = orderId;
- using var reader = command.ExecuteReader();
- return reader.Read() ? (reader.GetString(0), reader.GetInt32(1)) : null;
- }
- public int SaveOrder(OrderView order, int pickupPointId, string article, int quantity, string? customerFullName)
- {
- using var connection = Open();
- using var transaction = connection.BeginTransaction();
- var orderId = order.OrderId == 0 ? NextOrderId(connection, transaction) : order.OrderId;
- int? userId = null;
- if (!string.IsNullOrWhiteSpace(customerFullName))
- {
- using var userCmd = new SqlCommand("SELECT TOP (1) UserId FROM dbo.Users WHERE FullName = @name;", connection, transaction);
- userCmd.Parameters.Add("@name", SqlDbType.NVarChar, 250).Value = customerFullName.Trim();
- var existing = userCmd.ExecuteScalar();
- if (existing != null && existing != DBNull.Value)
- {
- userId = Convert.ToInt32(existing);
- }
- }
- var statusId = EnsureDictionaryValue(connection, transaction, "dbo.OrderStatuses", "OrderStatusId", order.Status);
- using (var command = new SqlCommand(order.OrderId == 0 ? @"
- INSERT INTO dbo.Orders (OrderId, UserId, PickupPointId, OrderStatusId, OrderDate, DeliveryDate, ReceiveCode)
- VALUES (@orderId, @userId, @pickupPointId, @statusId, @orderDate, @deliveryDate, @receiveCode);" : @"
- UPDATE dbo.Orders
- SET UserId=@userId, PickupPointId=@pickupPointId, OrderStatusId=@statusId, OrderDate=@orderDate,
- DeliveryDate=@deliveryDate, ReceiveCode=@receiveCode
- WHERE OrderId=@orderId;", connection, transaction))
- {
- command.Parameters.Add("@orderId", SqlDbType.Int).Value = orderId;
- command.Parameters.Add("@pickupPointId", SqlDbType.Int).Value = pickupPointId;
- command.Parameters.Add("@userId", SqlDbType.Int).Value = userId.HasValue ? (object)userId.Value : DBNull.Value;
- command.Parameters.Add("@statusId", SqlDbType.Int).Value = statusId;
- command.Parameters.Add("@orderDate", SqlDbType.Date).Value = order.OrderDate.HasValue ? order.OrderDate.Value : DBNull.Value;
- command.Parameters.Add("@deliveryDate", SqlDbType.Date).Value = order.DeliveryDate.HasValue ? order.DeliveryDate.Value : DBNull.Value;
- command.Parameters.Add("@receiveCode", SqlDbType.NVarChar, 20).Value = string.IsNullOrWhiteSpace(order.ReceiveCode) ? "000" : order.ReceiveCode;
- command.ExecuteNonQuery();
- }
- using (var deleteItems = new SqlCommand("DELETE FROM dbo.OrderItems WHERE OrderId=@orderId;", connection, transaction))
- {
- deleteItems.Parameters.Add("@orderId", SqlDbType.Int).Value = orderId;
- deleteItems.ExecuteNonQuery();
- }
- using (var insertItem = new SqlCommand(@"
- INSERT INTO dbo.OrderItems (OrderId, ProductId, Quantity, PriceAtOrder)
- SELECT @orderId, ProductId, @quantity, Price
- FROM dbo.Products
- WHERE Article=@article;", connection, transaction))
- {
- insertItem.Parameters.Add("@orderId", SqlDbType.Int).Value = orderId;
- insertItem.Parameters.Add("@quantity", SqlDbType.Int).Value = quantity;
- insertItem.Parameters.Add("@article", SqlDbType.NVarChar, 50).Value = article;
- if (insertItem.ExecuteNonQuery() == 0)
- {
- throw new InvalidOperationException("Товар с указанным артикулом не найден.");
- }
- }
- transaction.Commit();
- return orderId;
- }
- private SqlConnection Open()
- {
- var connection = new SqlConnection(_connectionString);
- connection.Open();
- return connection;
- }
- private List<string> LoadDictionary(string tableName)
- {
- using var connection = Open();
- using var command = new SqlCommand($"SELECT Name FROM {tableName} ORDER BY Name;", connection);
- using var reader = command.ExecuteReader();
- var result = new List<string>();
- while (reader.Read())
- {
- result.Add(reader.GetString(0));
- }
- return result;
- }
- public List<string> LoadUsers()
- {
- using var connection = Open();
- using var command = new SqlCommand("SELECT FullName FROM dbo.Users ORDER BY FullName;", connection);
- using var reader = command.ExecuteReader();
- var result = new List<string>();
- while (reader.Read())
- {
- result.Add(reader.GetString(0));
- }
- return result;
- }
- private static int EnsureDictionaryValue(SqlConnection connection, SqlTransaction transaction, string tableName, string idColumn, string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new InvalidOperationException("Не заполнено обязательное справочное значение.");
- }
- using (var select = new SqlCommand($"SELECT {idColumn} FROM {tableName} WHERE Name=@name;", connection, transaction))
- {
- select.Parameters.Add("@name", SqlDbType.NVarChar, 200).Value = name.Trim();
- var existing = select.ExecuteScalar();
- if (existing is not null && existing != DBNull.Value)
- {
- return Convert.ToInt32(existing);
- }
- }
- using var insert = new SqlCommand($"INSERT INTO {tableName} (Name) OUTPUT INSERTED.{idColumn} VALUES (@name);", connection, transaction);
- insert.Parameters.Add("@name", SqlDbType.NVarChar, 200).Value = name.Trim();
- return Convert.ToInt32(insert.ExecuteScalar());
- }
- private static int NextOrderId(SqlConnection connection, SqlTransaction transaction)
- {
- using var command = new SqlCommand("SELECT ISNULL(MAX(OrderId), 0) + 1 FROM dbo.Orders;", connection, transaction);
- return Convert.ToInt32(command.ExecuteScalar());
- }
- private static void AddDecimal(SqlCommand command, string name, decimal value)
- {
- var parameter = command.Parameters.Add(name, SqlDbType.Decimal);
- parameter.Precision = 18;
- parameter.Scale = 2;
- parameter.Value = value;
- }
- }
|