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) if (id <= 0)
{ {
@@ -275,9 +275,20 @@ SELECT @@ROWCOUNT;";
try try
{ {
using (var connection = CreateConnection()) using (var connection = CreateConnection())
using (var command = new SqlCommand(sql, connection))
{ {
connection.Open(); 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.CommandTimeout = 60;
command.Parameters.Add("@Id", SqlDbType.Int).Value = id; command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
@@ -286,10 +297,20 @@ SELECT @@ROWCOUNT;";
throw new InvalidOperationException("Запись SPNMTP для удаления не найдена."); throw new InvalidOperationException("Запись SPNMTP для удаления не найдена.");
} }
} }
return new SpnmtpDeleteResult
{
IsDeleted = true
};
}
} }
catch (SqlException ex) when (ex.Number == 547) 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); 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) private static bool IsSpnmtpDuplicateNameViolation(SqlException ex)
{ {
return ex != null return ex != null

View File

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

View File

@@ -132,7 +132,13 @@ namespace XLAB
RunMutationOperation(async delegate 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); await RefreshCoreAsync(null);
_dialogService.ShowInfo("Запись справочника удалена."); _dialogService.ShowInfo("Запись справочника удалена.");
}); });
@@ -254,14 +260,30 @@ namespace XLAB
} }
private async void RunBusyOperation(Func<Task> operation) private async void RunBusyOperation(Func<Task> operation)
{
try
{ {
await ExecuteBusyOperationAsync(operation); await ExecuteBusyOperationAsync(operation);
} }
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private async void RunMutationOperation(Func<Task> operation) private async void RunMutationOperation(Func<Task> operation)
{
try
{ {
await ExecuteMutationOperationAsync(operation); await ExecuteMutationOperationAsync(operation);
} }
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private void UpdateStatus() private void UpdateStatus()
{ {