This commit is contained in:
Курнат Андрей
2026-03-14 14:44:16 +03:00
parent 13e451acf5
commit c2548c377b
3 changed files with 124 additions and 11 deletions

View File

@@ -259,7 +259,7 @@ SELECT @@ROWCOUNT;";
}
}
public void DeleteSpnmtpItem(int id)
public SpnmtpDeleteResult DeleteSpnmtpItem(int id)
{
if (id <= 0)
{
@@ -275,9 +275,20 @@ SELECT @@ROWCOUNT;";
try
{
using (var connection = CreateConnection())
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
var blockers = LoadSpnmtpDeleteBlockers(connection, id);
if (blockers.Count > 0)
{
return new SpnmtpDeleteResult
{
IsDeleted = false,
WarningMessage = CreateSpnmtpDeleteBlockedMessage(blockers)
};
}
using (var command = new SqlCommand(sql, connection))
{
command.CommandTimeout = 60;
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
@@ -286,10 +297,20 @@ SELECT @@ROWCOUNT;";
throw new InvalidOperationException("Запись SPNMTP для удаления не найдена.");
}
}
return new SpnmtpDeleteResult
{
IsDeleted = true
};
}
}
catch (SqlException ex) when (ex.Number == 547)
{
throw new InvalidOperationException("Запись справочника используется в связанных данных и не может быть удалена.", ex);
return new SpnmtpDeleteResult
{
IsDeleted = false,
WarningMessage = CreateSpnmtpDeleteBlockedMessage(ex)
};
}
}
@@ -2337,6 +2358,69 @@ WHERE NMTP = @Name
innerException);
}
private static List<DeleteBlockerInfo> LoadSpnmtpDeleteBlockers(SqlConnection connection, int id)
{
const string sql = @"
SELECT blocker.TableName, blocker.LinkCount
FROM
(
SELECT N'TIPS' AS TableName, COUNT(*) AS LinkCount
FROM dbo.TIPS
WHERE IDSPNMTP = @Id
) blocker
WHERE blocker.LinkCount > 0
ORDER BY blocker.TableName;";
var blockers = new List<DeleteBlockerInfo>();
using (var command = new SqlCommand(sql, connection))
{
command.CommandTimeout = 60;
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
blockers.Add(new DeleteBlockerInfo
{
TableName = GetString(reader, "TableName"),
RowCount = GetInt32(reader, "LinkCount")
});
}
}
}
return blockers;
}
private static string CreateSpnmtpDeleteBlockedMessage(IEnumerable<DeleteBlockerInfo> blockers)
{
var blockerList = blockers == null
? new List<DeleteBlockerInfo>()
: blockers.Where(delegate(DeleteBlockerInfo blocker) { return blocker != null; }).ToList();
var details = blockerList.Count == 0
? "TIPS"
: string.Join(", ", blockerList.Select(delegate(DeleteBlockerInfo blocker)
{
return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount);
}));
return string.Format(
"Запись SPNMTP не может быть удалена, потому что на неё есть ссылки в таблицах: {0}. Подтверждённое ограничение БД: FK_TIPS_SPNMTP (dbo.TIPS.IDSPNMTP -> dbo.SPNMTP.IDSPNMTP).",
details);
}
private static string CreateSpnmtpDeleteBlockedMessage(SqlException ex)
{
if (ex != null && ex.Message.IndexOf("FK_TIPS_SPNMTP", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "Запись SPNMTP не может быть удалена, потому что на неё есть ссылки в таблице TIPS. Ограничение БД: FK_TIPS_SPNMTP (dbo.TIPS.IDSPNMTP -> dbo.SPNMTP.IDSPNMTP).";
}
return "Запись SPNMTP не может быть удалена из-за ограничения ссылочной целостности в БД.";
}
private static bool IsSpnmtpDuplicateNameViolation(SqlException ex)
{
return ex != null

View File

@@ -353,6 +353,13 @@ namespace XLAB
public string SpecialName { get; set; }
}
internal sealed class SpnmtpDeleteResult
{
public bool IsDeleted { get; set; }
public string WarningMessage { get; set; }
}
internal static class SpnmtpDirectoryRules
{
public const int NameMaxLength = 150;

View File

@@ -132,7 +132,13 @@ namespace XLAB
RunMutationOperation(async delegate
{
await Task.Run(delegate { _service.DeleteSpnmtpItem(selectedItem.Id); });
var deleteResult = await Task.Run(delegate { return _service.DeleteSpnmtpItem(selectedItem.Id); });
if (!deleteResult.IsDeleted)
{
_dialogService.ShowWarning(deleteResult.WarningMessage);
return;
}
await RefreshCoreAsync(null);
_dialogService.ShowInfo("Запись справочника удалена.");
});
@@ -254,14 +260,30 @@ namespace XLAB
}
private async void RunBusyOperation(Func<Task> operation)
{
try
{
await ExecuteBusyOperationAsync(operation);
}
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private async void RunMutationOperation(Func<Task> operation)
{
try
{
await ExecuteMutationOperationAsync(operation);
}
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private void UpdateStatus()
{