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 Электронная_Фармация.Classes; using System.IO; using System.Data.SQLite; namespace Электронная_Фармация.Forms { public partial class FCheckDatabaseIntegrary : Form { public FCheckDatabaseIntegrary() { InitializeComponent(); } string currentDirectoryPath = (System.IO.Directory.GetCurrentDirectory()); private void FCheckDatabaseIntegrary_Load(object sender, EventArgs e) { UiThemeHelper.ApplyToControlTree(this); checkDatabaseWasExists(); checkTablesExists(); this.Close(); } void checkDatabaseWasExists() { var dbPath = AppConfig.SqliteDbPath; var dir = Path.GetDirectoryName(dbPath); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (!File.Exists(dbPath)) { SQLiteConnection.CreateFile(dbPath); } } void checkTablesExists() { string connectionStringToLocalDB = AppConfig.SqliteConnectionString; //MessageBox.Show(connectionStringToLocalDB); using (SQLiteConnection conForCheckTables = new SQLiteConnection(connectionStringToLocalDB)) { try { conForCheckTables.Open(); string strCheckExistsSuppliers = @" create table if not exists [Suppliers] ( [idSuppliers] integer primary key AUTOINCREMENT not null, [codeSuppliers] integer not null, [SuppliersName] nvarchar(128) not null, [SuppliersTelephone] nvarchar(64), [SuppliersEmail] nvarchar(128), [SuppliersAddress] nvarchar(256), [MinimalSumOfOrder] real, [OrdersPath] text ) "; string strCheckExistsConsignees = @" create table if not exists [Consignees] ( [idConsignees] integer primary key AUTOINCREMENT not null, [codeConsignees] integer not null, [ConsigneesName] nvarchar(128) not null, [ConsigneesAddress] nvarchar(256) not null, [ConsigneesUseAsDefault] int(1) not null, [LocationId] nvarchar(64) ) "; string strCheckExistsInvoices = @" create table if not exists [Invoice] ( [idInvoice] integer primary key AUTOINCREMENT not null, [InvoiceNumber] nvarchar(128) not null, [InvoiceDate] integer not null, [CodeSupplier] integer not null, [CodeConsignees] integer not null, [SumWithoutNDS] real, [SumWithNDS] real, [SumNDS] real ) "; string strCheckExistsInvoiceItem = @" create table if not exists [InvoiceItem] ( [idInvoiceItem] integer primary key AUTOINCREMENT not null, [idGood] integer, [GoodCode] integer not null, [Good] nvarchar(256) not null, [ProducerName] nvarchar(256), [CountryName] nvarchar(256), [idInvoice] interger not null, [GoodsGount] integer not null, [PriceSupplierWithoutNDS] real, [PriceSupplierWithNDS] real, [PriceProducerWithoutNDS] real, [PriceProducerWithNDS] real, [NDS] integer, [JNVLS] int(1), [PriceReestr] real, [SumWithoutNDS] real, [SumWithNDS] real, [SumNDS] real, [Serial] nvarchar(24), [BestBefore] text, [Sertificate] nvarchar(128), [Marked] int(1) not null, [GTIN] nvarchar(14) ) "; string strCheckExistsTableGoods = @" create table if not exists [Goods] ( [idGood] integer primary key AUTOINCREMENT not null, [GoodCode] integer not null, [GoodName] nvarchar(256) not null, [idProducer] integer not null, [JNVLS] int(1), [CurrentReestrPrice] real, [idGoodsGroup] integer, [idGoodsShortNameForSearch] integer ) "; string strCheckExistsTableProducers = @" create table if not exists [Producers] ( [idProcuder] integer primary key AUTOINCREMENT not null, [ProducerCode] integer not null, [ProducerName] nvarchar(256) not null, [idCountry] integer not null ) "; string strCheckExistsTableCountries = @" create table if not exists [Countries] ( [idCountry] integer primary key AUTOINCREMENT not null, [CountryCode] integer not null, [CountryName] nvarchar(256) not null ) "; string strCheckExistsTableReestrPriceHistory = @" create table if not exists [ReestrPriceHistoryForGoods] ( [idReestrPriceHistory] integer primary key AUTOINCREMENT not null, [GoodCode] integer not null, [ReestrPriceDateCreate] text not null, [ReestrPrice] real not null, [ReestrPricePeriodFrom] text, [ReestrPricePeriodTo] text ) "; string strCheckExistsTablePriceHistory = @" create table if not exists [SuppliersPriceHistoryForGoods] ( [idSuppliersPriceHistoryForGoods] integer primary key AUTOINCREMENT not null, [GoodsCode] integer not null, [PriceDate] text not null, [MinPriceForGood] real, [AvgPriceForGood] real, [MaxPriceForGood] real ) "; string strCheckExistsTableGoodsGroup = @" create table if not exists [GoodsGroup] ( [idGoodsGroup] integer primary key AUTOINCREMENT not null, [GoodsGroupCode] integer not null, [GoodsGroupName] nvarchar(256) not null ) "; string strCheckExistsTableGoodsShortNameForSearch = @" create table if not exists [GoodsShortNameForSearch] ( [idGoodsShortNameForSearch] integer primary key AUTOINCREMENT not null, [GoodsShortNameForSearchCode] integer not null, [GoodsShortNameForSearchCodeName] nvarchar(255) not null ) "; string strCheckExistsTablePriceListFromSuppliers = @" create table if not exists [PriceListFromSuppliers] ( [idPriceListSuppliers] integer primary key AUTOINCREMENT not null, [ConsigneesCode] integer not null, [CodeSuppliers] integer not null, [PriceListDate] datetime ) "; string strCheckExistsTablePriceList = @" create table if not exists [PriceList] ( [guid_es] nvarchar(36) not null, [es_code] integer not null, [supplier_id] nvarchar(36) not null, [DrugName] nvarchar(256) not null COLLATE NOCASE, [SupplierName] nvarchar(256) not null, [Price] nvarchar(32), [Quantity] integer, [ExpiryPeriod] nvarchar(64), [Description] text, [Zakaz] nvarchar(64), [SummaZakaza] nvarchar(64), [id_PriceList_Item] integer primary key AUTOINCREMENT not null, [supplier_price_id] nvarchar(36) ) "; #region Старая таблица Прайс-листа // string strCheckExistsTablePriceList = @" // create table if not exists [PriceList] ( // [idPriceListSupplier] integer not null, // [ConsigneesCode] integer not null, // [idPriceList] integer primary key AUTOINCREMENT not null, // [GoodCode] integer, // [GoodName] nvarchar(256) not null COLLATE NOCASE, // [ProducerName] nvarchar(256), // [SupplierName] nvarchar(256) not null, // [BestBefore] text, // [JNVLS] int(1), // [PriceReestr] real, // [AvaibleCount] integer not null, // [PriceSupplierWithNDS] real not null, // [CountIWantBuy] integer, // [SumIWantBuy] real, // [CountryName] nvarchar(256), // [NDS] integer, // [PriceProducer] real, // [Marked] int(1) // ) //"; #endregion string strCheckExistsTableOrders = @" create table if not exists [Orders] ( [Id_Order] integer primary key AUTOINCREMENT not null, [OrderNumber] nvarchar(36) not null, [OrderDate] nvarchar(10) not null, [Id_Supplier] nvarchar(36) not null, [SupplierName] nvarchar(256) not null, [OrderedCountItems] integer, [SummaZakaza] nvarchar(32), [OrderState] nvarchar(32), [Comment] nvarchar(1024), [ConsigneeName] nvarchar(128), [RemoteOrderId] nvarchar(36) ) "; string strCheckExistsTableOrderItems = @" create table if not exists [OrderItems] ( [Id_Order_Item] integer primary key AUTOINCREMENT not null, [Id_Order] integer not null, [guid_es] nvarchar(36), [es_code] integer, [DrugName] nvarchar(256) not null COLLATE NOCASE, [Price] nvarchar(32), [Zakaz] integer, [SummaZakaza] nvarchar(32), [ExpiryPeriod] nvarchar(64), [RefuseItemsCount] integer, [supplier_price_id] nvarchar(36) ) "; #region старые таблицы Orders и OrderItem // string strCheckExistsTableOrders = @" // create table if not exists [Orders] ( // [idOrder] integer primary key AUTOINCREMENT not null, // [OrderNumber] nvarchar(10) not null, // [OrderDate] integer not null, // [codeSuppliers] integer not null, // [codeConsignees] integer not null, // [OrderedItemsCount] integer not null, // [OrderSum] real not null, // [RefuseItemsCount] integer, // [RefuseSum] real, // [Comment] text, // [OrderState] nvarchar(4) // ) //"; // string strCheckExistsTableOrderItems = @" // create table if not exists [OrderItems] ( // [idOrderItem] integer primary key AUTOINCREMENT not null, // [idOrder] integer not null, // [GoodCode] integer, // [GoodName] nvarchar(256) not null, // [OrderedCountItems] integer not null, // [SupplierPrice] real not null, // [SumOrderedItems] real not null, // [RefuseItemsCount] integer, // [BestBefore] text, // [ProducerName] nvarchar(256) // ) //"; #endregion string strCheckExistsTableTempOrderItems = @" create table if not exists [TempOrderItems] ( [ConsigneeName] nvarchar(128) not null, [guid_es] nvarchar(36) not null, [es_code] integer not null, [supplier_id] nvarchar(36) not null, [DrugName] nvarchar(256) not null COLLATE NOCASE, [SupplierName] nvarchar(256) not null, [Price] nvarchar(32), [Quantity] integer, [ExpiryPeriod] nvarchar(64), [Description] text, [Zakaz] real, [SummaZakaza] nvarchar(64), [id_PriceList_Item] integer not null, [supplier_price_id] nvarchar(36), primary key ([ConsigneeName], [id_PriceList_Item]) ) "; #region Старая временная таблица OrderItem // string strCheckExistsTableTempOrderItems = @" // create table if not exists [TempOrderItems] ( // [GoodCode] integer, // [GoodName] nvarchar(256) not null collate nocase, // [SupplierName] nvarchar(128) not null, // [ConsigneesName] nvarchar(128) not null, // [OrderedCountItems] integer not null, // [SumOrderedItems] real not null, // [SupplierPrice] real not null, // [BestBefore] text // ) //"; #endregion SQLiteCommand cmdCreateNotExistingsTables = conForCheckTables.CreateCommand(); cmdCreateNotExistingsTables.CommandText = strCheckExistsSuppliers; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsConsignees; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsInvoices; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsInvoiceItem; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoods; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoods; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableProducers; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableCountries; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableReestrPriceHistory; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTablePriceHistory; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoodsGroup; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoodsShortNameForSearch; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTablePriceListFromSuppliers; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTablePriceList; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableOrders; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableOrderItems; cmdCreateNotExistingsTables.ExecuteNonQuery(); cmdCreateNotExistingsTables.CommandText = strCheckExistsTableTempOrderItems; cmdCreateNotExistingsTables.ExecuteNonQuery(); // Миграция TempOrderItems под раздельную корзину по аптекам. // Проверяем наличие ConsigneeName и то, что id_PriceList_Item не является одинарным PK. bool hasConsigneeName = false; bool idPriceListItemIsSinglePk = false; using (var infoCmd = new SQLiteCommand("PRAGMA table_info([TempOrderItems]);", conForCheckTables)) using (var infoReader = infoCmd.ExecuteReader()) { while (infoReader.Read()) { var colName = infoReader["name"]?.ToString(); var pk = 0; try { pk = Convert.ToInt32(infoReader["pk"]); } catch { pk = 0; } if (string.Equals(colName, "ConsigneeName", StringComparison.OrdinalIgnoreCase)) { hasConsigneeName = true; } if (string.Equals(colName, "id_PriceList_Item", StringComparison.OrdinalIgnoreCase) && pk == 1) { idPriceListItemIsSinglePk = true; } } } if (!hasConsigneeName || idPriceListItemIsSinglePk) { string defaultConsignee; using (var defCmd = new SQLiteCommand( @"SELECT ifnull((SELECT ConsigneesName FROM Consignees WHERE ConsigneesUseAsDefault = 1 LIMIT 1), '')", conForCheckTables)) { defaultConsignee = defCmd.ExecuteScalar()?.ToString() ?? string.Empty; } using (var tx = conForCheckTables.BeginTransaction()) { using (var cmd = new SQLiteCommand(conForCheckTables)) { cmd.Transaction = tx; cmd.CommandText = @" CREATE TABLE IF NOT EXISTS [TempOrderItems_new] ( [ConsigneeName] nvarchar(128) not null, [guid_es] nvarchar(36) not null, [es_code] integer not null, [supplier_id] nvarchar(36) not null, [DrugName] nvarchar(256) not null COLLATE NOCASE, [SupplierName] nvarchar(256) not null, [Price] nvarchar(32), [Quantity] integer, [ExpiryPeriod] nvarchar(64), [Description] text, [Zakaz] real, [SummaZakaza] nvarchar(64), [id_PriceList_Item] integer not null, [supplier_price_id] nvarchar(36), primary key ([ConsigneeName], [id_PriceList_Item]) );"; cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("@defaultConsignee", defaultConsignee.Trim()); cmd.CommandText = @" INSERT INTO [TempOrderItems_new] ( [ConsigneeName], [guid_es], [es_code], [supplier_id], [DrugName], [SupplierName], [Price], [Quantity], [ExpiryPeriod], [Description], [Zakaz], [SummaZakaza], [id_PriceList_Item], [supplier_price_id] ) SELECT @defaultConsignee, [guid_es], [es_code], [supplier_id], [DrugName], [SupplierName], [Price], [Quantity], [ExpiryPeriod], [Description], [Zakaz], [SummaZakaza], [id_PriceList_Item], [supplier_price_id] FROM [TempOrderItems];"; cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); cmd.CommandText = @"DROP TABLE [TempOrderItems];"; cmd.ExecuteNonQuery(); cmd.CommandText = @"ALTER TABLE [TempOrderItems_new] RENAME TO [TempOrderItems];"; cmd.ExecuteNonQuery(); } tx.Commit(); } } // Перед seed-вставкой грузополучателей нужно гарантировать наличие LocationId, // иначе INSERT в Consignees (LocationId) упадёт на старых версиях БД. TryAddColumn(conForCheckTables, "Consignees", "LocationId", "nvarchar(64)"); // Seed-тестовые грузополучатели (аптеки) для удобства ручного тестирования. // Вставляем только если таблица пустая. using (var countConsigneesCmd = new SQLiteCommand( @"SELECT COUNT(*) FROM Consignees;", conForCheckTables)) { var countObj = countConsigneesCmd.ExecuteScalar(); var count = 0; try { count = Convert.ToInt32(countObj); } catch { count = 0; } if (count == 0) { var testLocationIds = new[] { "87368f6d-488b-41a9-b170-edc629522844", "c4cd845f-820d-45ac-a473-3df1a0b96feb", "d6187013-00f5-4c1b-b258-c670cf71d115" }; // Тестовые имена/адреса — можно менять под вашу тестовую среду. var testNames = new[] { "Тестовая аптека 1", "Тестовая аптека 2", "Тестовая аптека 3" }; var testAddresses = new[] { "Тестовый адрес 1", "Тестовый адрес 2", "Тестовый адрес 3" }; using (var tx = conForCheckTables.BeginTransaction()) { int nextCode; using (var nextCodeCmd = new SQLiteCommand( @"SELECT ifnull(MAX(codeConsignees), 0) + 1 FROM Consignees;", conForCheckTables, tx)) { nextCode = Convert.ToInt32(nextCodeCmd.ExecuteScalar()); } for (var i = 0; i < 3; i++) { using (var insertCmd = new SQLiteCommand( @"INSERT INTO Consignees (codeConsignees, ConsigneesName, ConsigneesAddress, ConsigneesUseAsDefault, LocationId) VALUES (@code, @name, @address, @isDefault, @loc);", conForCheckTables, tx)) { insertCmd.Parameters.AddWithValue("@code", nextCode + i); insertCmd.Parameters.AddWithValue("@name", testNames[i]); insertCmd.Parameters.AddWithValue("@address", testAddresses[i]); insertCmd.Parameters.AddWithValue("@isDefault", i == 0 ? 1 : 0); insertCmd.Parameters.AddWithValue("@loc", testLocationIds[i]); insertCmd.ExecuteNonQuery(); } } tx.Commit(); } } } TryAddColumn(conForCheckTables, "Orders", "ConsigneeName", "nvarchar(128)"); TryAddColumn(conForCheckTables, "Invoice", "SupplierName", "nvarchar(256)"); TryAddColumn(conForCheckTables, "Invoice", "ConsigneesName", "nvarchar(128)"); TryAddColumn(conForCheckTables, "Invoice", "InvoiceSum", "nvarchar(64)"); TryAddColumn(conForCheckTables, "Invoice", "RefuseSum", "nvarchar(64)"); TryAddColumn(conForCheckTables, "Invoice", "SourceOrderId", "integer"); TryAddColumn(conForCheckTables, "Invoice", "SourceOrderNumber", "nvarchar(36)"); TryAddColumn(conForCheckTables, "Invoice", "IsRequestedInvoice", "int(1)"); TryAddColumn(conForCheckTables, "Orders", "RemoteOrderId", "nvarchar(36)"); TryAddColumn(conForCheckTables, "PriceList", "TradeName", "nvarchar(256)"); TryAddColumn(conForCheckTables, "PriceList", "Dosage", "nvarchar(128)"); TryAddColumn(conForCheckTables, "PriceList", "MarkupPercent", "real"); TryAddColumn(conForCheckTables, "Consignees", "ClientMarkupPercent", "real"); ConsigneeHelper.MigrateGlobalLocationIdIfNeeded(conForCheckTables); } catch (Exception ex) { try { var logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); Directory.CreateDirectory(logDir); var logPath = Path.Combine( logDir, $"db-integrity-err-{DateTime.Now:yyyy-MM-dd}.log"); File.AppendAllText( logPath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {ex}{Environment.NewLine}{Environment.NewLine}", Encoding.UTF8); } catch { // Логирование не должно скрывать исходную ошибку. } UiDialogs.ShowError($"Возникла ошибка при проверке локальной базы на целостность.\n{ex}", "Ошибка целостности", this); } finally { conForCheckTables.Close(); } } } private static void TryAddColumn(SQLiteConnection connection, string tableName, string columnName, string columnType) { using (var infoCmd = new SQLiteCommand($"PRAGMA table_info([{tableName}])", connection)) using (var reader = infoCmd.ExecuteReader()) { while (reader.Read()) { if (string.Equals(reader["name"].ToString(), columnName, StringComparison.OrdinalIgnoreCase)) { return; } } } using (var alterCmd = new SQLiteCommand($"ALTER TABLE [{tableName}] ADD COLUMN [{columnName}] {columnType}", connection)) { alterCmd.ExecuteNonQuery(); } } } }