using System; using System.Collections.Generic; using System.Data; using System.Linq; using Microsoft.Data.SqlClient; namespace XLAB2 { internal sealed class EkzDirectoryService { private static readonly string[] CascadingEkzChildTables = { "EKZMK", "EKZMCP" }; private static readonly string[] CascadingEkzMkChildTables = { "EKZMKFCTVL", "EKZMKDH", "EKZMKEKZK", "EKZMKND", "KSPELEKZMK" }; public int AddEkzItem(EkzDirectoryItem item) { var normalizedItem = NormalizeEkzItem(item); const string sql = @" INSERT INTO dbo.EKZ ( IDTPRZ, IDFRPDV, KLSIPR, NNZV, NNIN, DSEKZ, GUIDEKZ, IsDeleted ) VALUES ( @TypeSizeId, @OwnerOrganizationId, 1, @SerialNumber, @InventoryNumber, @Notes, @Guid, 0 ); SELECT CAST(SCOPE_IDENTITY() AS int);"; using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); EnsureEkzIsUnique(connection, normalizedItem.TypeSizeId, normalizedItem.OwnerOrganizationId, normalizedItem.SerialNumber, null); command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = normalizedItem.TypeSizeId; command.Parameters.Add("@OwnerOrganizationId", SqlDbType.Int).Value = normalizedItem.OwnerOrganizationId; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, EkzDirectoryRules.SerialNumberMaxLength).Value = normalizedItem.SerialNumber; ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@InventoryNumber", SqlDbType.VarChar, EkzDirectoryRules.InventoryNumberMaxLength, normalizedItem.InventoryNumber); ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@Notes", SqlDbType.VarChar, EkzDirectoryRules.NotesMaxLength, normalizedItem.Notes); command.Parameters.Add("@Guid", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid(); return Convert.ToInt32(command.ExecuteScalar()); } } public EkzDeletePreview GetEkzDeletePreview(int id) { if (id <= 0) { return new EkzDeletePreview { CanDelete = false, ImpactItems = Array.Empty(), WarningMessage = "Не выбрана запись EKZ для удаления." }; } using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) { connection.Open(); return BuildEkzDeletePreview(connection, null, id); } } public EkzDeleteResult DeleteEkzItem(int id) { if (id <= 0) { throw new InvalidOperationException("Не выбрана запись EKZ для удаления."); } try { using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { var preview = BuildEkzDeletePreview(connection, transaction, id); if (!preview.CanDelete) { transaction.Rollback(); return new EkzDeleteResult { IsDeleted = false, ImpactItems = preview.ImpactItems ?? Array.Empty(), WarningMessage = preview.WarningMessage }; } var impactItems = new List(); AddImpactItem(impactItems, "EKZMKFCTVL", DeleteEkzMkFctvl(connection, transaction, id)); AddImpactItem(impactItems, "EKZMKDH", DeleteEkzMkDh(connection, transaction, id)); AddImpactItem(impactItems, "EKZMKEKZK", DeleteEkzMkEkzk(connection, transaction, id)); AddImpactItem(impactItems, "EKZMKND", DeleteEkzMkNd(connection, transaction, id)); AddImpactItem(impactItems, "KSPELEKZMK", DeleteKspelEkzMk(connection, transaction, id)); AddImpactItem(impactItems, "DMS", DeleteEkzDms(connection, transaction, id)); AddImpactItem(impactItems, "EKZMK", DeleteEkzMk(connection, transaction, id)); AddImpactItem(impactItems, "EKZMCP", DeleteEkzMcp(connection, transaction, id)); var deletedEkzCount = DeleteEkz(connection, transaction, id); if (deletedEkzCount == 0) { transaction.Rollback(); return new EkzDeleteResult { IsDeleted = false, ImpactItems = Array.Empty(), WarningMessage = "Запись EKZ для удаления не найдена." }; } AddImpactItem(impactItems, "EKZ", deletedEkzCount); transaction.Commit(); return new EkzDeleteResult { IsDeleted = true, ImpactItems = OrderImpactItems(impactItems) }; } } } catch (SqlException ex) when (ex.Number == 547) { return new EkzDeleteResult { IsDeleted = false, ImpactItems = Array.Empty(), WarningMessage = CreateEkzDeleteFailedMessage(ex) }; } } public IReadOnlyList LoadEkzItems() { const string sql = @" SELECT z.IDEKZ AS Id, z.IDTPRZ AS TypeSizeId, areas.NMOI AS MeasurementAreaName, names.NMTP AS InstrumentName, tips.TP AS TypeName, tprz.DPZN AS RangeText, tprz.HRTC AS AccuracyText, tprz.NNGSRS AS RegistryNumber, z.IDFRPDV AS OwnerOrganizationId, ownerOrg.NMFRPD AS OwnerOrganizationName, z.NNZV AS SerialNumber, z.NNIN AS InventoryNumber, CAST(z.DSEKZ AS nvarchar(max)) AS Notes FROM dbo.EKZ z JOIN dbo.TPRZ tprz ON tprz.IDTPRZ = z.IDTPRZ JOIN dbo.TIPS tips ON tips.IDTIPS = tprz.IDTIPS JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV WHERE ISNULL(z.IsDeleted, 0) = 0 ORDER BY ownerOrg.NMFRPD, areas.NMOI, names.NMTP, tips.TP, tprz.DPZN, z.NNZV, z.IDEKZ;"; var items = new List(); using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); using (var reader = command.ExecuteReader()) { while (reader.Read()) { items.Add(new EkzDirectoryItem { Id = ReferenceDirectorySqlHelpers.GetInt32(reader, "Id"), TypeSizeId = ReferenceDirectorySqlHelpers.GetInt32(reader, "TypeSizeId"), MeasurementAreaName = ReferenceDirectorySqlHelpers.GetString(reader, "MeasurementAreaName"), InstrumentName = ReferenceDirectorySqlHelpers.GetString(reader, "InstrumentName"), TypeName = ReferenceDirectorySqlHelpers.GetString(reader, "TypeName"), RangeText = ReferenceDirectorySqlHelpers.GetString(reader, "RangeText"), AccuracyText = ReferenceDirectorySqlHelpers.GetString(reader, "AccuracyText"), RegistryNumber = ReferenceDirectorySqlHelpers.GetString(reader, "RegistryNumber"), OwnerOrganizationId = ReferenceDirectorySqlHelpers.GetInt32(reader, "OwnerOrganizationId"), OwnerOrganizationName = ReferenceDirectorySqlHelpers.GetString(reader, "OwnerOrganizationName"), SerialNumber = ReferenceDirectorySqlHelpers.GetString(reader, "SerialNumber"), InventoryNumber = ReferenceDirectorySqlHelpers.GetString(reader, "InventoryNumber"), Notes = ReferenceDirectorySqlHelpers.GetString(reader, "Notes") }); } } } return items; } public IReadOnlyList LoadEkzMkItems(int instrumentId) { const string sql = @" SELECT m.IDEKZMK AS CardId, m.IDEKZ AS InstrumentId, verificationType.NMVDMK AS VerificationTypeName, organization.NMFRPD AS VerificationOrganizationName, m.NNZVPV AS DocumentNumber, verificationDocument.NNDMS AS VerificationDocumentNumber, verificationDocument.DTDMS AS VerificationDocumentDate, m.PRMK AS PeriodMonths, m.DTPRM AS AcceptedOn, m.DTMKPL AS PlannedOn, m.DTMKFK AS PerformedOn, m.DTVDM AS IssuedOn, m.GDN AS IsPassed, CAST(m.DSEKZMK AS nvarchar(max)) AS Notes FROM dbo.EKZMK m LEFT JOIN dbo.SPVDMK verificationType ON verificationType.IDSPVDMK = m.IDSPVDMK LEFT JOIN dbo.FRPD organization ON organization.IDFRPD = m.IDFRPD OUTER APPLY ( SELECT TOP (1) d.NND AS NNDMS, d.DTD AS DTDMS FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.FRDMS frdms ON frdms.IDFRDMS = d.IDFRDMS JOIN dbo.SPVDD spvdd ON spvdd.IDSPVDD = frdms.IDSPVDD WHERE d.IDOD = m.IDEKZMK AND vdd.IDSPVDOD = 2 AND spvdd.IDSPVDD IN (2, 6, 8) ORDER BY d.DTD DESC ) verificationDocument WHERE m.IDEKZ = @InstrumentId ORDER BY ISNULL(m.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, m.IDEKZMK DESC;"; var items = new List(); using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId; using (var reader = command.ExecuteReader()) { while (reader.Read()) { items.Add(new EkzMkDirectoryItem { CardId = ReferenceDirectorySqlHelpers.GetInt32(reader, "CardId"), InstrumentId = ReferenceDirectorySqlHelpers.GetInt32(reader, "InstrumentId"), VerificationTypeName = ReferenceDirectorySqlHelpers.GetString(reader, "VerificationTypeName"), VerificationOrganizationName = ReferenceDirectorySqlHelpers.GetString(reader, "VerificationOrganizationName"), DocumentNumber = ReferenceDirectorySqlHelpers.GetString(reader, "DocumentNumber"), VerificationDocumentNumber = ReferenceDirectorySqlHelpers.GetString(reader, "VerificationDocumentNumber"), VerificationDocumentDate = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "VerificationDocumentDate"), PeriodMonths = ReferenceDirectorySqlHelpers.GetInt32(reader, "PeriodMonths"), AcceptedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "AcceptedOn"), PlannedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "PlannedOn"), PerformedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "PerformedOn"), IssuedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "IssuedOn"), IsPassed = ReferenceDirectorySqlHelpers.GetNullableBoolean(reader, "IsPassed"), Notes = ReferenceDirectorySqlHelpers.GetString(reader, "Notes") }); } } } return items; } public IReadOnlyList LoadFrpdReferences() { return ReferenceDirectorySqlHelpers.LoadLookupItems(@" SELECT fr.IDFRPD AS Id, fr.NMFRPD AS Name FROM dbo.FRPD fr WHERE NULLIF(LTRIM(RTRIM(fr.NMFRPD)), '') IS NOT NULL ORDER BY fr.NMFRPD, fr.IDFRPD;"); } public IReadOnlyList LoadTypeSizeReferences() { return ReferenceDirectorySqlHelpers.LoadLookupItems(@" SELECT tprz.IDTPRZ AS Id, LTRIM(RTRIM( COALESCE(NULLIF(areas.NMOI, N'') + N' / ', N'') + COALESCE(NULLIF(names.NMTP, N'') + N' / ', N'') + COALESCE(NULLIF(tips.TP, N''), N'') + CASE WHEN NULLIF(LTRIM(RTRIM(tprz.DPZN)), N'') IS NULL THEN N'' ELSE N' / ' + tprz.DPZN END + CASE WHEN NULLIF(LTRIM(RTRIM(CONVERT(nvarchar(50), tprz.NNGSRS))), N'') IS NULL THEN N'' ELSE N' / № ГР ' + CONVERT(nvarchar(50), tprz.NNGSRS) END )) AS Name FROM dbo.TPRZ tprz JOIN dbo.TIPS tips ON tips.IDTIPS = tprz.IDTIPS JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI ORDER BY areas.NMOI, names.NMTP, tips.TP, tprz.DPZN, tprz.IDTPRZ;"); } public void UpdateEkzItem(EkzDirectoryItem item) { var normalizedItem = NormalizeEkzItem(item); if (normalizedItem.Id <= 0) { throw new InvalidOperationException("Не выбрана запись EKZ для изменения."); } const string sql = @" UPDATE dbo.EKZ SET IDTPRZ = @TypeSizeId, IDFRPDV = @OwnerOrganizationId, NNZV = @SerialNumber, NNIN = @InventoryNumber, DSEKZ = @Notes WHERE IDEKZ = @Id; SELECT @@ROWCOUNT;"; using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); EnsureEkzIsUnique(connection, normalizedItem.TypeSizeId, normalizedItem.OwnerOrganizationId, normalizedItem.SerialNumber, normalizedItem.Id); command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id; command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = normalizedItem.TypeSizeId; command.Parameters.Add("@OwnerOrganizationId", SqlDbType.Int).Value = normalizedItem.OwnerOrganizationId; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, EkzDirectoryRules.SerialNumberMaxLength).Value = normalizedItem.SerialNumber; ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@InventoryNumber", SqlDbType.VarChar, EkzDirectoryRules.InventoryNumberMaxLength, normalizedItem.InventoryNumber); ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@Notes", SqlDbType.VarChar, EkzDirectoryRules.NotesMaxLength, normalizedItem.Notes); if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Запись EKZ для изменения не найдена."); } } } private static EkzDeletePreview BuildEkzDeletePreview(SqlConnection connection, SqlTransaction transaction, int id) { if (!EkzExists(connection, transaction, id)) { return new EkzDeletePreview { CanDelete = false, ImpactItems = Array.Empty(), WarningMessage = "Запись EKZ для удаления не найдена." }; } var cardIds = LoadEkzMkCardIds(connection, transaction, id); var blockers = new List(); blockers.AddRange(ReferenceDirectorySqlHelpers.LoadDeleteBlockersFromForeignKeys(connection, transaction, "EKZ", id, CascadingEkzChildTables)); blockers.AddRange(LoadUnhandledDeleteBlockers(connection, transaction, "EKZMK", cardIds, CascadingEkzMkChildTables)); var impactItems = BuildImpactItems(connection, transaction, id, cardIds); var mergedBlockers = MergeBlockers(blockers); if (mergedBlockers.Count > 0) { return new EkzDeletePreview { CanDelete = false, ImpactItems = impactItems, WarningMessage = CreateEkzCascadeBlockedMessage(mergedBlockers) }; } return new EkzDeletePreview { CanDelete = true, ImpactItems = impactItems, ConfirmationMessage = CreateEkzDeleteConfirmationMessage(impactItems) }; } private static IReadOnlyList BuildImpactItems(SqlConnection connection, SqlTransaction transaction, int instrumentId, IReadOnlyCollection cardIds) { var impactItems = new List(); AddImpactItem(impactItems, "EKZ", 1); AddImpactItem(impactItems, "EKZMK", cardIds == null ? 0 : cardIds.Count); AddImpactItem(impactItems, "DMS", CountEkzDms(connection, transaction, instrumentId)); AddImpactItem(impactItems, "EKZMKFCTVL", CountEkzMkFctvl(connection, transaction, instrumentId)); AddImpactItem(impactItems, "EKZMKDH", CountEkzMkDh(connection, transaction, instrumentId)); AddImpactItem(impactItems, "EKZMKEKZK", CountEkzMkEkzk(connection, transaction, instrumentId)); AddImpactItem(impactItems, "EKZMKND", CountEkzMkNd(connection, transaction, instrumentId)); AddImpactItem(impactItems, "KSPELEKZMK", CountKspelEkzMk(connection, transaction, instrumentId)); AddImpactItem(impactItems, "EKZMCP", CountEkzMcp(connection, transaction, instrumentId)); return OrderImpactItems(impactItems); } private static IReadOnlyList OrderImpactItems(IEnumerable impactItems) { var order = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "EKZ", 1 }, { "EKZMK", 2 }, { "DMS", 3 }, { "EKZMKFCTVL", 4 }, { "EKZMKDH", 5 }, { "EKZMKEKZK", 6 }, { "EKZMKND", 7 }, { "KSPELEKZMK", 8 }, { "EKZMCP", 9 } }; return (impactItems ?? Enumerable.Empty()) .Where(delegate(EkzDeleteImpactItem item) { return item != null && item.RowCount > 0; }) .OrderBy(delegate(EkzDeleteImpactItem item) { int value; return order.TryGetValue(item.TableName ?? string.Empty, out value) ? value : int.MaxValue; }) .ThenBy(delegate(EkzDeleteImpactItem item) { return item.TableName; }, StringComparer.OrdinalIgnoreCase) .ToList(); } private static void AddImpactItem(ICollection impactItems, string tableName, int rowCount) { if (impactItems == null || string.IsNullOrWhiteSpace(tableName) || rowCount <= 0) { return; } impactItems.Add(new EkzDeleteImpactItem { TableName = tableName, RowCount = rowCount }); } private static string CreateEkzDeleteConfirmationMessage(IEnumerable impactItems) { var items = OrderImpactItems(impactItems).ToList(); var lines = new List(); if (items.Count == 0) { lines.Add("Будет физически удалена только запись EKZ."); } else { lines.Add("Будут физически удалены записи:"); foreach (var item in items) { lines.Add(string.Format("{0}: {1}", item.TableName, item.RowCount)); } } lines.Add(string.Empty); lines.Add("Продолжить?"); return string.Join(Environment.NewLine, lines.ToArray()); } private static string CreateEkzCascadeBlockedMessage(IEnumerable blockers) { return string.Format( "Экземпляр не может быть удалён автоматически. Есть связанные записи в таблицах, которые не входят в каскад удаления: {0}.", FormatBlockerDetails(blockers)); } private static string CreateEkzDeleteFailedMessage(SqlException ex) { var suffix = ex == null || string.IsNullOrWhiteSpace(ex.Message) ? string.Empty : " " + ex.Message.Trim(); return "Экземпляр не может быть удалён из-за ограничений ссылочной целостности БД." + suffix; } private static string FormatBlockerDetails(IEnumerable blockers) { var details = string.Join(", ", (blockers ?? Enumerable.Empty()) .Where(delegate(DeleteBlockerInfo blocker) { return blocker != null && blocker.RowCount > 0; }) .OrderBy(delegate(DeleteBlockerInfo blocker) { return blocker.TableName; }, StringComparer.OrdinalIgnoreCase) .Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); return string.IsNullOrWhiteSpace(details) ? "связанные данные" : details; } private static List MergeBlockers(IEnumerable blockers) { return (blockers ?? Enumerable.Empty()) .Where(delegate(DeleteBlockerInfo blocker) { return blocker != null && blocker.RowCount > 0 && !string.IsNullOrWhiteSpace(blocker.TableName); }) .GroupBy(delegate(DeleteBlockerInfo blocker) { return blocker.TableName; }, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return new DeleteBlockerInfo { TableName = group.Key, RowCount = group.Sum(delegate(DeleteBlockerInfo blocker) { return blocker.RowCount; }) }; }) .OrderBy(delegate(DeleteBlockerInfo blocker) { return blocker.TableName; }, StringComparer.OrdinalIgnoreCase) .ToList(); } private static List LoadUnhandledDeleteBlockers(SqlConnection connection, SqlTransaction transaction, string parentTableName, IEnumerable ids, IEnumerable excludedChildTables) { var blockers = new List(); foreach (var id in (ids ?? Enumerable.Empty()).Where(delegate(int value) { return value > 0; }).Distinct()) { blockers.AddRange(ReferenceDirectorySqlHelpers.LoadDeleteBlockersFromForeignKeys(connection, transaction, parentTableName, id, excludedChildTables)); } return MergeBlockers(blockers); } private static bool EkzExists(SqlConnection connection, SqlTransaction transaction, int id) { const string sql = @" SELECT COUNT(1) FROM dbo.EKZ WHERE IDEKZ = @Id;"; return ExecuteScalarForId(connection, transaction, sql, id) > 0; } private static List LoadEkzMkCardIds(SqlConnection connection, SqlTransaction transaction, int instrumentId) { const string sql = @" SELECT IDEKZMK FROM dbo.EKZMK WHERE IDEKZ = @InstrumentId ORDER BY IDEKZMK;"; return ExecuteIdList(connection, transaction, sql, "@InstrumentId", instrumentId); } private static int CountEkzMcp(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.EKZMCP WHERE IDEKZ = @InstrumentId;", instrumentId); } private static int CountEkzMkFctvl(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.EKZMKFCTVL child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId;", instrumentId); } private static int CountEkzMkDh(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.EKZMKDH child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId;", instrumentId); } private static int CountEkzMkEkzk(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.EKZMKEKZK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId;", instrumentId); } private static int CountEkzMkNd(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.EKZMKND child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId;", instrumentId); } private static int CountKspelEkzMk(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.KSPELEKZMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId;", instrumentId); } private static int CountEkzDms(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" SELECT COUNT(*) FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD WHERE m.IDEKZ = @InstrumentId AND vdd.IDSPVDOD = 2;", instrumentId); } private static int DeleteEkzMcp(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE FROM dbo.EKZMCP WHERE IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkzMkFctvl(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE child FROM dbo.EKZMKFCTVL child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkzMkDh(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE child FROM dbo.EKZMKDH child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkzMkEkzk(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE child FROM dbo.EKZMKEKZK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkzMkNd(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE child FROM dbo.EKZMKND child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteKspelEkzMk(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE child FROM dbo.KSPELEKZMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkzDms(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD WHERE m.IDEKZ = @InstrumentId AND vdd.IDSPVDOD = 2; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkzMk(SqlConnection connection, SqlTransaction transaction, int instrumentId) { return ExecuteScalarForInstrument(connection, transaction, @" DELETE FROM dbo.EKZMK WHERE IDEKZ = @InstrumentId; SELECT @@ROWCOUNT;", instrumentId); } private static int DeleteEkz(SqlConnection connection, SqlTransaction transaction, int id) { return ExecuteScalarForId(connection, transaction, @" DELETE FROM dbo.EKZ WHERE IDEKZ = @Id; SELECT @@ROWCOUNT;", id); } private static int ExecuteScalarForInstrument(SqlConnection connection, SqlTransaction transaction, string sql, int instrumentId) { using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId; return Convert.ToInt32(command.ExecuteScalar()); } } private static int ExecuteScalarForId(SqlConnection connection, SqlTransaction transaction, string sql, int id) { using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add("@Id", SqlDbType.Int).Value = id; return Convert.ToInt32(command.ExecuteScalar()); } } private static List ExecuteIdList(SqlConnection connection, SqlTransaction transaction, string sql, string parameterName, int parameterValue) { var result = new List(); using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add(parameterName, SqlDbType.Int).Value = parameterValue; using (var reader = command.ExecuteReader()) { while (reader.Read()) { result.Add(reader.GetInt32(0)); } } } return result; } private static string NormalizeOptional(string value) { return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); } private static EkzDirectoryItem NormalizeEkzItem(EkzDirectoryItem item) { if (item == null) { throw new InvalidOperationException("Не переданы данные записи EKZ."); } var normalizedItem = new EkzDirectoryItem { Id = item.Id, TypeSizeId = item.TypeSizeId, OwnerOrganizationId = item.OwnerOrganizationId, SerialNumber = NormalizeOptional(item.SerialNumber), InventoryNumber = NormalizeOptional(item.InventoryNumber), Notes = NormalizeOptional(item.Notes) }; if (normalizedItem.TypeSizeId <= 0) { throw new InvalidOperationException("Не указан типоразмер СИ."); } if (normalizedItem.OwnerOrganizationId <= 0) { throw new InvalidOperationException("Не указана организация-владелец."); } if (string.IsNullOrWhiteSpace(normalizedItem.SerialNumber)) { throw new InvalidOperationException("Не указан заводской номер."); } if (normalizedItem.SerialNumber.Length > EkzDirectoryRules.SerialNumberMaxLength) { throw new InvalidOperationException(string.Format("Заводской номер не должен превышать {0} символов.", EkzDirectoryRules.SerialNumberMaxLength)); } if (!string.IsNullOrWhiteSpace(normalizedItem.InventoryNumber) && normalizedItem.InventoryNumber.Length > EkzDirectoryRules.InventoryNumberMaxLength) { throw new InvalidOperationException(string.Format("Инвентарный номер не должен превышать {0} символов.", EkzDirectoryRules.InventoryNumberMaxLength)); } if (!string.IsNullOrWhiteSpace(normalizedItem.Notes) && normalizedItem.Notes.Length > EkzDirectoryRules.NotesMaxLength) { throw new InvalidOperationException(string.Format("Примечание не должно превышать {0} символов.", EkzDirectoryRules.NotesMaxLength)); } return normalizedItem; } private static void EnsureEkzIsUnique(SqlConnection connection, int typeSizeId, int ownerOrganizationId, string serialNumber, int? excludeId) { const string sql = @" SELECT TOP (1) z.IDEKZ FROM dbo.EKZ z WHERE z.IDTPRZ = @TypeSizeId AND z.IDFRPDV = @OwnerOrganizationId AND z.NNZV = @SerialNumber AND ISNULL(z.IsDeleted, 0) = 0 AND (@ExcludeId IS NULL OR z.IDEKZ <> @ExcludeId) ORDER BY z.IDEKZ DESC;"; using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds(); command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = typeSizeId; command.Parameters.Add("@OwnerOrganizationId", SqlDbType.Int).Value = ownerOrganizationId; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, EkzDirectoryRules.SerialNumberMaxLength).Value = serialNumber; ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ExcludeId", excludeId); if (command.ExecuteScalar() != null) { throw new InvalidOperationException("Экземпляр с таким типоразмером, владельцем и заводским номером уже существует."); } } } } }