Files
XLAB/XLAB2/FrpdDirectoryService.cs
Курнат Андрей a47a7a5a3b edit
2026-03-19 23:31:41 +03:00

561 lines
23 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Data;
using Microsoft.Data.SqlClient;
using System.Linq;
namespace XLAB2
{
internal sealed class FrpdDirectoryService
{
public int AddFrpdItem(FrpdDirectoryItem item)
{
var normalizedItem = NormalizeFrpdItem(item);
var guidForInsert = string.IsNullOrWhiteSpace(normalizedItem.Guid)
? Guid.NewGuid().ToString().ToUpperInvariant()
: normalizedItem.Guid;
const string sql = @"
INSERT INTO dbo.FRPD
(
IDFRPDR,
NMFRPD,
KDFRPDLC,
FRPDGUID,
DTSZFRPD,
DTLKFRPD
)
VALUES
(
@ParentId,
@Name,
@LocalCode,
@Guid,
@CreatedOn,
@LiquidatedOn
);
SELECT CAST(SCOPE_IDENTITY() AS int);";
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
EnsureFrpdGuidIsUnique(connection, guidForInsert, null);
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ParentId", normalizedItem.ParentId);
command.Parameters.Add("@Name", SqlDbType.VarChar, FrpdDirectoryRules.NameMaxLength).Value = normalizedItem.Name;
ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@LocalCode", SqlDbType.VarChar, FrpdDirectoryRules.LocalCodeMaxLength, normalizedItem.LocalCode);
ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@Guid", SqlDbType.VarChar, FrpdDirectoryRules.GuidMaxLength, guidForInsert);
ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@CreatedOn", normalizedItem.CreatedOn);
ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@LiquidatedOn", normalizedItem.LiquidatedOn);
try
{
return Convert.ToInt32(command.ExecuteScalar());
}
catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "IX_FRPD_FRPDGUID"))
{
throw CreateFrpdDuplicateGuidException(guidForInsert);
}
}
}
public int AddFrpdvdItem(FrpdvdDirectoryItem item)
{
var normalizedItem = NormalizeFrpdvdItem(item);
const string sql = @"
INSERT INTO dbo.FRPDVD
(
IDFRPD,
IDSPVDDO
)
VALUES
(
@FrpdId,
@ActivityId
);
SELECT CAST(SCOPE_IDENTITY() AS int);";
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
EnsureFrpdvdIsUnique(connection, normalizedItem.FrpdId, normalizedItem.ActivityId, null);
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@FrpdId", SqlDbType.Int).Value = normalizedItem.FrpdId;
command.Parameters.Add("@ActivityId", SqlDbType.Int).Value = normalizedItem.ActivityId;
try
{
return Convert.ToInt32(command.ExecuteScalar());
}
catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "XAK1FRPDVD"))
{
throw CreateFrpdvdDuplicateException();
}
}
}
public DirectoryDeleteResult DeleteFrpdItem(int id)
{
if (id <= 0)
{
throw new InvalidOperationException("Не выбрана запись FRPD для удаления.");
}
const string sql = @"
DELETE FROM dbo.FRPD
WHERE IDFRPD = @Id;
SELECT @@ROWCOUNT;";
try
{
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
{
connection.Open();
var blockers = ReferenceDirectorySqlHelpers.LoadDeleteBlockersFromForeignKeys(connection, "FRPD", id);
if (blockers.Count > 0)
{
return new DirectoryDeleteResult
{
IsDeleted = false,
WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPD", blockers)
};
}
using (var command = new SqlCommand(sql, connection))
{
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
{
throw new InvalidOperationException("Запись FRPD для удаления не найдена.");
}
}
return new DirectoryDeleteResult
{
IsDeleted = true
};
}
}
catch (SqlException ex) when (ex.Number == 547)
{
return new DirectoryDeleteResult
{
IsDeleted = false,
WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPD", ex)
};
}
}
public DirectoryDeleteResult DeleteFrpdvdItem(int id)
{
if (id <= 0)
{
throw new InvalidOperationException("Не выбрана запись FRPDVD для удаления.");
}
const string sql = @"
DELETE FROM dbo.FRPDVD
WHERE IDFRPDVD = @Id;
SELECT @@ROWCOUNT;";
try
{
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
{
connection.Open();
var blockers = ReferenceDirectorySqlHelpers.LoadDeleteBlockersFromForeignKeys(connection, "FRPDVD", id);
if (blockers.Count > 0)
{
return new DirectoryDeleteResult
{
IsDeleted = false,
WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPDVD", blockers)
};
}
using (var command = new SqlCommand(sql, connection))
{
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
{
throw new InvalidOperationException("Запись FRPDVD для удаления не найдена.");
}
}
return new DirectoryDeleteResult
{
IsDeleted = true
};
}
}
catch (SqlException ex) when (ex.Number == 547)
{
return new DirectoryDeleteResult
{
IsDeleted = false,
WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPDVD", ex)
};
}
}
public IReadOnlyList<FrpdDirectoryItem> LoadFrpdItems()
{
const string sql = @"
SELECT
fr.IDFRPD AS Id,
fr.IDFRPDR AS ParentId,
parent.NMFRPD AS ParentName,
fr.NMFRPD AS Name,
fr.KDFRPDLC AS LocalCode,
fr.FRPDGUID AS Guid,
fr.DTSZFRPD AS CreatedOn,
fr.DTLKFRPD AS LiquidatedOn,
ISNULL(
STUFF((
SELECT ', ' + activity.ActivityName
FROM
(
SELECT DISTINCT sp.NMVDDO AS ActivityName
FROM dbo.FRPDVD link
JOIN dbo.SPVDDO sp ON sp.IDSPVDDO = link.IDSPVDDO
WHERE link.IDFRPD = fr.IDFRPD
) activity
ORDER BY activity.ActivityName
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 2, ''),
''
) AS ActivityNames
FROM dbo.FRPD fr
LEFT JOIN dbo.FRPD parent ON parent.IDFRPD = fr.IDFRPDR
ORDER BY fr.NMFRPD, fr.IDFRPD;";
var items = new List<FrpdDirectoryItem>();
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 FrpdDirectoryItem
{
ActivityNames = ReferenceDirectorySqlHelpers.GetString(reader, "ActivityNames"),
CreatedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "CreatedOn"),
Guid = ReferenceDirectorySqlHelpers.GetString(reader, "Guid"),
Id = ReferenceDirectorySqlHelpers.GetInt32(reader, "Id"),
LiquidatedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "LiquidatedOn"),
LocalCode = ReferenceDirectorySqlHelpers.GetString(reader, "LocalCode"),
Name = ReferenceDirectorySqlHelpers.GetString(reader, "Name"),
ParentId = ReferenceDirectorySqlHelpers.GetNullableInt32(reader, "ParentId"),
ParentName = ReferenceDirectorySqlHelpers.GetString(reader, "ParentName")
});
}
}
}
return items;
}
public IReadOnlyList<DirectoryLookupItem> LoadFrpdReferences()
{
return ReferenceDirectorySqlHelpers.LoadLookupItems(@"
SELECT
fr.IDFRPD AS Id,
fr.NMFRPD AS Name
FROM dbo.FRPD fr
ORDER BY fr.NMFRPD, fr.IDFRPD;");
}
public IReadOnlyList<FrpdvdDirectoryItem> LoadFrpdvdItems(int frpdId)
{
const string sql = @"
SELECT
link.IDFRPDVD AS Id,
link.IDFRPD AS FrpdId,
link.IDSPVDDO AS ActivityId,
sp.NMVDDO AS ActivityName
FROM dbo.FRPDVD link
JOIN dbo.SPVDDO sp ON sp.IDSPVDDO = link.IDSPVDDO
WHERE link.IDFRPD = @FrpdId
ORDER BY sp.NMVDDO, link.IDFRPDVD;";
var items = new List<FrpdvdDirectoryItem>();
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@FrpdId", SqlDbType.Int).Value = frpdId;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
items.Add(new FrpdvdDirectoryItem
{
ActivityId = ReferenceDirectorySqlHelpers.GetInt32(reader, "ActivityId"),
ActivityName = ReferenceDirectorySqlHelpers.GetString(reader, "ActivityName"),
FrpdId = ReferenceDirectorySqlHelpers.GetInt32(reader, "FrpdId"),
Id = ReferenceDirectorySqlHelpers.GetInt32(reader, "Id")
});
}
}
}
return items;
}
public IReadOnlyList<DirectoryLookupItem> LoadSpvddoReferences()
{
return ReferenceDirectorySqlHelpers.LoadLookupItems(@"
SELECT
sp.IDSPVDDO AS Id,
sp.NMVDDO AS Name
FROM dbo.SPVDDO sp
ORDER BY sp.NMVDDO, sp.IDSPVDDO;");
}
public void UpdateFrpdItem(FrpdDirectoryItem item)
{
var normalizedItem = NormalizeFrpdItem(item);
if (normalizedItem.Id <= 0)
{
throw new InvalidOperationException("Не выбрана запись FRPD для изменения.");
}
const string sql = @"
UPDATE dbo.FRPD
SET IDFRPDR = @ParentId,
NMFRPD = @Name,
KDFRPDLC = @LocalCode,
FRPDGUID = @Guid,
DTSZFRPD = @CreatedOn,
DTLKFRPD = @LiquidatedOn
WHERE IDFRPD = @Id;
SELECT @@ROWCOUNT;";
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
EnsureFrpdGuidIsUnique(connection, normalizedItem.Guid, normalizedItem.Id);
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id;
ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ParentId", normalizedItem.ParentId);
command.Parameters.Add("@Name", SqlDbType.VarChar, FrpdDirectoryRules.NameMaxLength).Value = normalizedItem.Name;
ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@LocalCode", SqlDbType.VarChar, FrpdDirectoryRules.LocalCodeMaxLength, normalizedItem.LocalCode);
ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@Guid", SqlDbType.VarChar, FrpdDirectoryRules.GuidMaxLength, normalizedItem.Guid);
ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@CreatedOn", normalizedItem.CreatedOn);
ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@LiquidatedOn", normalizedItem.LiquidatedOn);
try
{
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
{
throw new InvalidOperationException("Запись FRPD для изменения не найдена.");
}
}
catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "IX_FRPD_FRPDGUID"))
{
throw CreateFrpdDuplicateGuidException(normalizedItem.Guid);
}
}
}
public void UpdateFrpdvdItem(FrpdvdDirectoryItem item)
{
var normalizedItem = NormalizeFrpdvdItem(item);
if (normalizedItem.Id <= 0)
{
throw new InvalidOperationException("Не выбрана запись FRPDVD для изменения.");
}
const string sql = @"
UPDATE dbo.FRPDVD
SET IDSPVDDO = @ActivityId
WHERE IDFRPDVD = @Id;
SELECT @@ROWCOUNT;";
using (var connection = ReferenceDirectorySqlHelpers.CreateConnection())
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
EnsureFrpdvdIsUnique(connection, normalizedItem.FrpdId, normalizedItem.ActivityId, normalizedItem.Id);
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id;
command.Parameters.Add("@ActivityId", SqlDbType.Int).Value = normalizedItem.ActivityId;
try
{
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
{
throw new InvalidOperationException("Запись FRPDVD для изменения не найдена.");
}
}
catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "XAK1FRPDVD"))
{
throw CreateFrpdvdDuplicateException();
}
}
}
private static InvalidOperationException CreateFrpdDuplicateGuidException(string guid)
{
return new InvalidOperationException(string.Format("GUID подразделения \"{0}\" уже существует в справочнике.", guid));
}
private static InvalidOperationException CreateFrpdvdDuplicateException()
{
return new InvalidOperationException("Выбранный вид деятельности уже существует у этой организации/подразделения.");
}
private static void EnsureFrpdGuidIsUnique(SqlConnection connection, string guid, int? excludeId)
{
if (string.IsNullOrWhiteSpace(guid))
{
return;
}
const string sql = @"
SELECT COUNT(1)
FROM dbo.FRPD
WHERE FRPDGUID = @Guid
AND (@ExcludeId IS NULL OR IDFRPD <> @ExcludeId);";
using (var command = new SqlCommand(sql, connection))
{
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@Guid", SqlDbType.VarChar, FrpdDirectoryRules.GuidMaxLength).Value = guid;
ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ExcludeId", excludeId);
if (Convert.ToInt32(command.ExecuteScalar()) > 0)
{
throw CreateFrpdDuplicateGuidException(guid);
}
}
}
private static void EnsureFrpdvdIsUnique(SqlConnection connection, int frpdId, int activityId, int? excludeId)
{
const string sql = @"
SELECT COUNT(1)
FROM dbo.FRPDVD
WHERE IDFRPD = @FrpdId
AND IDSPVDDO = @ActivityId
AND (@ExcludeId IS NULL OR IDFRPDVD <> @ExcludeId);";
using (var command = new SqlCommand(sql, connection))
{
command.CommandTimeout = ReferenceDirectorySqlHelpers.GetCommandTimeoutSeconds();
command.Parameters.Add("@FrpdId", SqlDbType.Int).Value = frpdId;
command.Parameters.Add("@ActivityId", SqlDbType.Int).Value = activityId;
ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ExcludeId", excludeId);
if (Convert.ToInt32(command.ExecuteScalar()) > 0)
{
throw CreateFrpdvdDuplicateException();
}
}
}
private static string NormalizeRequired(string value, int maxLength, string fieldDisplayName)
{
var normalizedValue = string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
if (normalizedValue.Length == 0)
{
throw new InvalidOperationException(string.Format("Укажите {0}.", fieldDisplayName));
}
if (normalizedValue.Length > maxLength)
{
throw new InvalidOperationException(string.Format("{0} не должно превышать {1} символов.", fieldDisplayName, maxLength));
}
return normalizedValue;
}
private static string NormalizeNullable(string value, int maxLength, string fieldDisplayName)
{
var normalizedValue = string.IsNullOrWhiteSpace(value) ? null : value.Trim();
if (normalizedValue != null && normalizedValue.Length > maxLength)
{
throw new InvalidOperationException(string.Format("{0} не должно превышать {1} символов.", fieldDisplayName, maxLength));
}
return normalizedValue;
}
private static FrpdDirectoryItem NormalizeFrpdItem(FrpdDirectoryItem item)
{
if (item == null)
{
throw new InvalidOperationException("Не передана запись FRPD.");
}
var normalizedItem = new FrpdDirectoryItem
{
CreatedOn = item.CreatedOn,
Guid = NormalizeNullable(item.Guid, FrpdDirectoryRules.GuidMaxLength, "GUID подразделения"),
Id = item.Id,
LiquidatedOn = item.LiquidatedOn,
LocalCode = NormalizeNullable(item.LocalCode, FrpdDirectoryRules.LocalCodeMaxLength, "Локальный код организации/подразделения"),
Name = NormalizeRequired(item.Name, FrpdDirectoryRules.NameMaxLength, "организацию/подразделение"),
ParentId = item.ParentId.HasValue && item.ParentId.Value > 0 ? item.ParentId : null
};
if (normalizedItem.Id > 0
&& normalizedItem.ParentId.HasValue
&& normalizedItem.ParentId.Value == normalizedItem.Id)
{
throw new InvalidOperationException("Организация/подразделение не может ссылаться на себя как на родительскую запись.");
}
return normalizedItem;
}
private static FrpdvdDirectoryItem NormalizeFrpdvdItem(FrpdvdDirectoryItem item)
{
if (item == null)
{
throw new InvalidOperationException("Не передана запись FRPDVD.");
}
if (item.FrpdId <= 0)
{
throw new InvalidOperationException("Не выбрана организация/подразделение для вида деятельности.");
}
if (item.ActivityId <= 0)
{
throw new InvalidOperationException("Укажите вид деятельности организации.");
}
return new FrpdvdDirectoryItem
{
ActivityId = item.ActivityId,
FrpdId = item.FrpdId,
Id = item.Id
};
}
}
}