Изменение метода отчистки таблицы.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
|
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
|
||||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors;
|
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors;
|
||||||
|
using Pf2eModel;
|
||||||
|
|
||||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
|
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
|
||||||
|
|
||||||
@@ -11,11 +12,6 @@ namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
|
|||||||
/// <param name="loader"></param>
|
/// <param name="loader"></param>
|
||||||
internal class AonprdDataBuilder(AonprdLoader loader)
|
internal class AonprdDataBuilder(AonprdLoader loader)
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Класс работы с базой данных.
|
|
||||||
/// </summary>
|
|
||||||
public readonly Pf2eDatabase Database = Pf2eDatabase.Instance;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Основной класс для работы с данными Архива Нефиса.
|
/// Основной класс для работы с данными Архива Нефиса.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -38,7 +34,10 @@ internal class AonprdDataBuilder(AonprdLoader loader)
|
|||||||
{
|
{
|
||||||
Console.WriteLine("Truncating all old data...");
|
Console.WriteLine("Truncating all old data...");
|
||||||
|
|
||||||
Database.ExecuteCommand("SELECT f_truncate_tables();");
|
using Pf2eDbContext context = new();
|
||||||
|
string cmd = context.Entities.Truncate() + "\n" + context.TruncateAll();
|
||||||
|
|
||||||
|
Console.WriteLine(cmd);
|
||||||
|
|
||||||
Console.WriteLine("Truncation completed!");
|
Console.WriteLine("Truncation completed!");
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -2,13 +2,12 @@
|
|||||||
using Konsole;
|
using Konsole;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.Compendium;
|
using Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.Compendium;
|
||||||
|
using Pf2eModel;
|
||||||
|
|
||||||
namespace Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.DataBuilder;
|
namespace Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.DataBuilder;
|
||||||
|
|
||||||
internal class PF2eFoundryDataBuilder
|
internal class PF2eFoundryDataBuilder
|
||||||
{
|
{
|
||||||
public Pf2eDatabase Database = Pf2eDatabase.Instance;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Загрузчик данных.
|
/// Загрузчик данных.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -51,7 +50,10 @@ internal class PF2eFoundryDataBuilder
|
|||||||
{
|
{
|
||||||
Console.WriteLine("Truncating all old data...");
|
Console.WriteLine("Truncating all old data...");
|
||||||
|
|
||||||
Database.ExecuteCommand("SELECT f_truncate_tables();");
|
using Pf2eDbContext context = new();
|
||||||
|
string cmd = context.Entities.Truncate() + "\n" + context.TruncateAll();
|
||||||
|
|
||||||
|
Console.WriteLine(cmd);
|
||||||
|
|
||||||
Console.WriteLine("Truncation completed!");
|
Console.WriteLine("Truncation completed!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
using System.Text.RegularExpressions;
|
|
||||||
using Npgsql;
|
|
||||||
|
|
||||||
namespace Pf2eDataScrapper;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Main class for database connection and operations.
|
|
||||||
/// </summary>
|
|
||||||
public partial class Pf2eDatabase
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Подключение к базе данных.
|
|
||||||
/// </summary>
|
|
||||||
public readonly NpgsqlConnection Connection;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Имя пользователя для подключения к базе данных.
|
|
||||||
/// </summary>
|
|
||||||
public readonly string Username;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Название базы данных.
|
|
||||||
/// </summary>
|
|
||||||
public readonly string DatabaseName;
|
|
||||||
|
|
||||||
private Pf2eDatabase()
|
|
||||||
{
|
|
||||||
Username = UsernamePattern().Match(EnvSettings.DatabaseConnection).Groups[1].Value;
|
|
||||||
DatabaseName = DatabaseNamePattern().Match(EnvSettings.DatabaseConnection).Groups[1].Value;
|
|
||||||
|
|
||||||
Connection = new(EnvSettings.DatabaseConnection);
|
|
||||||
Connection.Open();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Pf2eDatabase()
|
|
||||||
{
|
|
||||||
Connection.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Singleton instance of the database connection manager.
|
|
||||||
/// </summary>
|
|
||||||
public static Pf2eDatabase Instance { get; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Current transaction associated with this database connection.
|
|
||||||
/// </summary>
|
|
||||||
public NpgsqlTransaction? Transaction { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Begin a new transaction on the database connection.
|
|
||||||
/// </summary>
|
|
||||||
public void StartTransaction()
|
|
||||||
{
|
|
||||||
if (Transaction != null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Transaction already started.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Transaction = Connection.BeginTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Commit the current transaction to the database.
|
|
||||||
/// </summary>
|
|
||||||
public void Commit()
|
|
||||||
{
|
|
||||||
if (Transaction == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("No transaction started.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Transaction.Commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Execute a SQL command against the database.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sql">The SQL command to execute</param>
|
|
||||||
public void ExecuteCommand(string sql)
|
|
||||||
{
|
|
||||||
NpgsqlCommand command = GetCommand(sql);
|
|
||||||
|
|
||||||
command.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new SQL command for the database connection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sql">The SQL command string</param>
|
|
||||||
/// <returns>A new NpgsqlCommand object</returns>
|
|
||||||
public NpgsqlCommand GetCommand(string sql)
|
|
||||||
{
|
|
||||||
return new(sql, Connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public void RebuildDatabase()
|
|
||||||
{
|
|
||||||
// Закрываем текущее соединение
|
|
||||||
Connection.Close();
|
|
||||||
|
|
||||||
// Получение имён
|
|
||||||
var databaseNamePattern = DatabaseNamePattern();
|
|
||||||
var userConnection = databaseNamePattern.Replace(EnvSettings.DatabaseConnection, ";");
|
|
||||||
var databaseName = databaseNamePattern.Match(EnvSettings.DatabaseConnection).Groups[1].Value;
|
|
||||||
var username = UserNamePattern().Match(EnvSettings.DatabaseConnection).Groups[1].Value;
|
|
||||||
|
|
||||||
// Временное подключение к базе данных
|
|
||||||
NpgsqlConnection tmpConnection = new(userConnection);
|
|
||||||
tmpConnection.Open();
|
|
||||||
|
|
||||||
// Удаляем базу данных
|
|
||||||
NpgsqlCommand dropCommand = new($"DROP DATABASE \"{databaseName}\";", tmpConnection);
|
|
||||||
dropCommand.ExecuteNonQuery();
|
|
||||||
|
|
||||||
// Создаём новую базу данных
|
|
||||||
NpgsqlCommand createCommand = new($@"
|
|
||||||
CREATE DATABASE {databaseName}
|
|
||||||
WITH OWNER = {username}
|
|
||||||
ENCODING = 'UTF8'
|
|
||||||
CONNECTION LIMIT = -1;
|
|
||||||
", tmpConnection);
|
|
||||||
createCommand.ExecuteNonQuery();
|
|
||||||
|
|
||||||
string[] permissionCommands = [
|
|
||||||
$"GRANT TEMPORARY, CONNECT ON DATABASE {databaseName} TO PUBLIC;",
|
|
||||||
$"GRANT ALL ON DATABASE {databaseName} TO {username} WITH GRANT OPTION;",
|
|
||||||
$"GRANT ALL ON DATABASE {databaseName} TO postgres;"
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach (var command in permissionCommands)
|
|
||||||
{
|
|
||||||
NpgsqlCommand permissionCommand = new(command, tmpConnection);
|
|
||||||
permissionCommand.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Закрываем временное соединение
|
|
||||||
tmpConnection.Close();
|
|
||||||
|
|
||||||
// Заново создаём соединение
|
|
||||||
Connection = new NpgsqlConnection(EnvSettings.DatabaseConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
[GeneratedRegex(@"(?:^|;)Database=(.*?)(?:$|;)")]
|
|
||||||
private static partial Regex DatabaseNamePattern();
|
|
||||||
|
|
||||||
[GeneratedRegex(@"(?:^|;)User=(.*?)(?:$|;)")]
|
|
||||||
private static partial Regex UsernamePattern();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
|
||||||
|
namespace Pf2eModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Класс, обеспецивающий общий способ для отчистки данных таблиц.
|
||||||
|
///
|
||||||
|
/// Источник: https://www.codeproject.com/Articles/5339402/Delete-All-Rows-in-Entity-Framework-Core-6
|
||||||
|
/// </summary>
|
||||||
|
public static class EfCleanHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Определение полного названия таблицы по служебному классу.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entityType">Служебный класс, определяющий таблицу базы данных.</param>
|
||||||
|
/// <param name="defaultSchemaName">Схема таблицы по умолчанию (<c>"public"</c> для PostgresSQL)</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string GetName(IEntityType entityType, string defaultSchemaName = "public")
|
||||||
|
{
|
||||||
|
object? schema = entityType.FindAnnotation("Relational:Schema")?.Value;
|
||||||
|
|
||||||
|
string tableName =
|
||||||
|
entityType.GetAnnotation("Relational:TableName")?.Value?.ToString()
|
||||||
|
?? throw new($"Не могу определить название таблицы для типа {entityType}");
|
||||||
|
|
||||||
|
string schemaName = schema?.ToString() ?? defaultSchemaName;
|
||||||
|
|
||||||
|
string name = $"\"{schemaName}\".\"{tableName}\"";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Определение полного названия таблицы по типу сущности.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Тип искомой сущности.</typeparam>
|
||||||
|
/// <param name="dbContext">Контекст, в котором производится поиск таблицы.</param>
|
||||||
|
/// <returns>Строковое представление названия таблицы.</returns>
|
||||||
|
public static string TableName<T>(DbContext dbContext)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
IEntityType entityType =
|
||||||
|
dbContext.Model.FindEntityType(typeof(T))
|
||||||
|
?? throw new($"Не могу определить название таблицы для класса {typeof(T)}");
|
||||||
|
|
||||||
|
return GetName(entityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Определение полного названия таблицы по типу сущности.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Тип искомой сущности.</typeparam>
|
||||||
|
/// <param name="dbSet">CLR-представление таблицы, название которой требуется определить.</param>
|
||||||
|
/// <returns>Строковое представление названия таблицы.</returns>
|
||||||
|
public static string TableName<T>(DbSet<T> dbSet)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
IEntityType entityType = dbSet.EntityType;
|
||||||
|
return GetName(entityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Отчистка содержимого таблицы.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Тип сущности, таблицу которой необходимо отчистить.</typeparam>
|
||||||
|
/// <param name="dbSet">CLR-представление таблицы, которую требуется отчистить.</param>
|
||||||
|
/// <returns>Строковое представление выполненной SQL-команды.</returns>
|
||||||
|
public static string Truncate<T>(this DbSet<T> dbSet)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
string cmd = $"TRUNCATE TABLE {TableName(dbSet)} CASCADE;";
|
||||||
|
DbContext context = dbSet.GetService<ICurrentDbContext>().Context;
|
||||||
|
context.Database.ExecuteSqlRaw(cmd);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение SQL-команды отчистки содержимого всех таблиц базы данных.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Контекст базы данных, в которой необходимо отчистить все строки.</param>
|
||||||
|
/// <returns>Строковое представление выполненных SQL-команды.</returns>
|
||||||
|
public static string TruncateAll(this DbContext context)
|
||||||
|
{
|
||||||
|
IEnumerable<IEntityType> tables = context.Model.GetEntityTypes();
|
||||||
|
List<string> cmdList = [];
|
||||||
|
|
||||||
|
foreach (IEntityType entityType in tables)
|
||||||
|
{
|
||||||
|
string cmd = $"TRUNCATE TABLE {GetName(entityType)} CASCADE;";
|
||||||
|
context.Database.ExecuteSqlRaw(cmd);
|
||||||
|
cmdList.Add(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join('\n', cmdList);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,25 +12,6 @@ public partial class Function : Migration
|
|||||||
{
|
{
|
||||||
migrationBuilder.Sql(
|
migrationBuilder.Sql(
|
||||||
"""
|
"""
|
||||||
CREATE OR REPLACE FUNCTION f_truncate_tables()
|
|
||||||
RETURNS void
|
|
||||||
LANGUAGE plpgsql AS
|
|
||||||
$func$
|
|
||||||
BEGIN
|
|
||||||
EXECUTE
|
|
||||||
(SELECT 'TRUNCATE TABLE '
|
|
||||||
|| string_agg(format('%I.%I', schemaname, tablename), ', ')
|
|
||||||
|| ' CASCADE;'
|
|
||||||
FROM pg_tables
|
|
||||||
WHERE schemaname = 'public'
|
|
||||||
AND tablename != '__EFMigrationsHistory'
|
|
||||||
);
|
|
||||||
END
|
|
||||||
$func$;
|
|
||||||
"""
|
|
||||||
);
|
|
||||||
migrationBuilder.Sql(
|
|
||||||
"""
|
|
||||||
CREATE OR REPLACE FUNCTION f_drop_tables()
|
CREATE OR REPLACE FUNCTION f_drop_tables()
|
||||||
RETURNS void
|
RETURNS void
|
||||||
LANGUAGE plpgsql AS
|
LANGUAGE plpgsql AS
|
||||||
|
|||||||
@@ -52,7 +52,12 @@ public partial class Pf2eDbContext
|
|||||||
private void BindEntity<T>(EntityTypeBuilder<T> entity)
|
private void BindEntity<T>(EntityTypeBuilder<T> entity)
|
||||||
where T : class, IEntity
|
where T : class, IEntity
|
||||||
{
|
{
|
||||||
entity.HasOne(e => e.Entity).WithOne().HasForeignKey<T>(e => e.Id).IsRequired();
|
entity
|
||||||
|
.HasOne(e => e.Entity)
|
||||||
|
.WithOne()
|
||||||
|
.HasForeignKey<T>(e => e.Id)
|
||||||
|
.IsRequired()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user