пятница, 4 июля 2025 г.

Otus, HomeWork, 25.07.01

Otus, HomeWork, 25.07.01

Create Tables Create_Shop2.sql

D:\VC25\Otus\CS\Projects\Shop\Scripts\

---------------------------------------------------------------------------------------------------

USE Shop3


-- Create Tables


-- Таблица Products

CREATE TABLE Products (

    ProductID INT IDENTITY(1,1) PRIMARY KEY,

    ProductName NVARCHAR(255) NOT NULL,

    Description NVARCHAR(MAX),

    Price NUMERIC(10, 2) NOT NULL CONSTRAINT CK_Product_Price CHECK (Price > 0),

    QuantityInStock INT NOT NULL CONSTRAINT CK_Product_Qty CHECK (QuantityInStock >= 0)

);

Go

-- Таблица Users

CREATE TABLE Users (

    UserID INT IDENTITY(1,1) PRIMARY KEY,

    UserName NVARCHAR(255) NOT NULL,

    Email NVARCHAR(255) UNIQUE NOT NULL,

    RegistrationDate DATETIME DEFAULT GETDATE()

);

Go

-- Таблица Orders

CREATE TABLE Orders (

    OrderID INT IDENTITY(1,1) PRIMARY KEY,

    UserID INT FOREIGN KEY REFERENCES Users(UserID),

    OrderDate DATETIME DEFAULT GETDATE(),

    Status NVARCHAR(50) NOT NULL

);

Go


-- Таблица OrderDetails

CREATE TABLE OrderDetails (

    OrderDetailID INT IDENTITY(1,1) PRIMARY KEY,

    OrderID INT FOREIGN KEY REFERENCES Orders(OrderID),

    ProductID INT FOREIGN KEY REFERENCES Products(ProductID),

    Quantity INT NOT NULL CONSTRAINT CK_OrderDetails_Quantity CHECK (Quantity > 0),

    TotalCost NUMERIC(10, 2) NOT NULL CONSTRAINT CK_OrderDetails_TotalCost CHECK (TotalCost > 0)

);

GO

-- ------------------------------------------------------

--USE Shop3

DELETE FROM Products


INSERT INTO Products (ProductName, Description, Price, QuantityInStock)

VALUES

('jackson usa', 'USA Signature guitars', 1500.00, 20),

('Gibson LP', 'Gibson Les Paul Tribute', 2000.00, 15),

('Schecter Plat', 'Schecter Platinium', 1000.00, 30),

('Fender Am', 'Fender American Professional', 2500.00, 10),

('Ibanez 550', 'Ibanez RG550', 2600.00, 42),

('Gibson SG', 'Gibson SG Standard', 800.00, 40),

('Schecter BJ', 'Schecter Black Jack', 1200.00, 26),

('Schecter Reaper', 'Schecter Reaper usa', 1400.00, 42);

GO


DELETE FROM Users

GO


INSERT INTO Users (UserName, Email)

VALUES

('Rony James Dio', 'rony@jamesdio.com'),

('Janis Joplin', 'janis@joplin.com');

GO

-----------------------------------------------------------

--USE Shop3


DELETE FROM Orders


INSERT INTO Orders (UserID, Status)

VALUES

(1, 'pending'), 

(1, 'completed'), 

(1, 'completed');


go


INSERT INTO Orders (UserID, Status)

VALUES

(2, 'pending'), 

(2, 'completed');


go


DELETE FROM OrderDetails


INSERT INTO OrderDetails (OrderID, ProductID, Quantity, TotalCost)

VALUES

(1, 1, 2, 10), 

(1, 2, 1, 10), 

(2, 3, 3, 10),

(2, 4, 5, 10),

(3, 5, 1,10),

(4, 6, 3,10),

(5, 7, 5, 10),

(5, 8, 1, 10);


go


--USE Shop3


SELECT TOP (1000)

    O.[OrderID],

    U.[UserID],

    U.[UserName],

    U.[Email],

    U.[RegistrationDate],

    O.[OrderDate],

    O.[Status],

    OD.[OrderDetailID],

    OD.[ProductID],

    OD.[Quantity],

    OD.[TotalCost],

    P.[ProductName],

    P.[Description],

    P.[Price],

    P.[QuantityInStock]

FROM 

    [dbo].[Orders] AS O

INNER JOIN 

    [dbo].[Users] AS U ON O.[UserID] = U.[UserID]

INNER JOIN 

    [dbo].[OrderDetails] AS OD ON O.[OrderID] = OD.[OrderID]

INNER JOIN 

    [dbo].[Products] AS P ON OD.[ProductID] = P.[ProductID];


GO


Otus, HomeTask, 25.07.01

Otus, HomeTask, 25.07.01

Домашнее задание

Создание виртуальной базы данных магазина в PostgreSQL

Цель:

В этом домашнем задании вы научитесь создавать базу данных с таблицами, а также писать скрипты с использованием основных ключевых слов. Итогом будет два файла со скриптами: один для создания всех необходимых таблиц с ключами и связями, а другой для запросов.


Описание/Пошаговая инструкция выполнения домашнего задания:

Спроектируйте и создайте структуру базы данных для виртуального магазина, следуя этому плану:

  1. Таблица "Products" (Продукты):
  • ProductID (Основной ключ)
  • ProductName (Название продукта)
  • Description (Описание)
  • Price (Цена)
  • QuantityInStock (Количество на складе)


  1. Таблица "Users" (Пользователи):
  • UserID (Основной ключ)
  • UserName (Имя пользователя)
  • Email (Электронная почта)
  • RegistrationDate (Дата регистрации)


  1. Таблица "Orders" (Заказы):
  • OrderID (Основной ключ)
  • UserID (Внешний ключ)
  • OrderDate (Дата заказа)
  • Status (Статус)


  1. Таблица "OrderDetails" (Детали заказа):
  • OrderDetailID (Основной ключ)
  • OrderID (Внешний ключ)
  • ProductID (Внешний ключ)
  • Quantity (Количество)
  • TotalCost (Общая стоимость)


  1. Установление связей:
  • Связь между "Users" и "Orders"
  • Связь между "Orders" и "OrderDetails"
  • Связь между "Products" и "OrderDetails"


  1. SQL запросы:
  • Добавление нового продукта
  • Обновление цены продукта
  • Выбор всех заказов определенного пользователя
  • Расчет общей стоимости заказа
  • Подсчет количества товаров на складе
  • Получение 5 самых дорогих товаров
  • Список товаров с низким запасом (менее 5 штук)


Критерии оценки:

Создание таблиц "Products" и "Users": 2 балла
Создание таблиц "Orders" и "OrderDetails": 2 балла
Установление связей между таблицами: 1 балл
Добавление нового продукта и обновление цены продукта: 1 балл
Выбор всех заказов определенного пользователя и расчет общей стоимости заказа: 1 балл
Подсчет товаров на складе и получение 5 самых дорогих товаров: 2 балла
Список товаров с низким запасом: 1 балл

Минимальное количество баллов для выполнения задания: 6 баллов.


Компетенции:
  • Работа с базами данных
    • - создавать реляционную базу данных PostgreSQL
    • - писать скрипты создания таблиц

Рекомендуем сдать до: 07.07.2025

четверг, 29 мая 2025 г.

Chad, Project, LoggerC03,

Chad, Project, LoggerC03, Migration

LoggerC01 EF - tag

https://ask.chadgpt.ru/share/8e69d16f-7e85-44a5-bc43-8594e9869c9b

D:\VC25\gs.trade.core\Logger\Logger.sln

D:\VC25\gs.trade.core\Logger\LoggerLib\LoggerLib.csproj

D:\VC25\gs.trade.core\Logger\CaLogger01\CaLogger01.csproj

ConnectionString:

"Server=WIN-0EMQO515V3S\\SQLDVLP25;Database=LoggerC03;Trusted_Connection=True; Trust Server Certificate = True;"

Need to Install

CaLogger01 and LoggerLib
Microsoft.EntityFrameworkCore.Design

Migrations: CaLogger01

PM> Add-Migration Initial

Build started...

Build failed.

PM> dotnet ef migrations add InitialCreate --project LoggerLib --startup-project CaLogger01

Build started...

Build succeeded.

Your startup project 'CaLogger01' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.

PM> dotnet ef migrations add InitialCreate --project LoggerLib --startup-project CaLogger01

Build started...

Build succeeded.

Unable to create a 'DbContext' of type 'RuntimeType'. The exception 'Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[LoggerLib.LoggerDbContext]' while attempting to activate 'LoggerLib.LoggerDbContext'.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

PM> dotnet ef migrations add InitialCreate --project LoggerLib --startup-project CaLogger01

Build started...

Build succeeded.

Done. To undo this action, use 'ef migrations remove'

PM>    dotnet ef database update --project LoggerLib --startup-project CaLogger01

Build started...

Build succeeded.

Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)

PM>    dotnet ef database update --project LoggerLib --startup-project CaLogger01

Build started...

Build succeeded.

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

PM>    dotnet ef database update --project LoggerLib --startup-project CaLogger01

Build started...

Build succeeded.

Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long.

Applying migration '20250530005634_InitialCreate'.

Done.

PM> 

среда, 28 мая 2025 г.

DataBase, Create, Auto

DataBase, Create, Auto

https://giga.chat/link/gcsacidXhW

  • Создание базы данных вручную:
  • Самый простой путь — предварительно создать базу данных через SQL Server Management Studio (SSMS)
  • или другой удобный инструмент.
  • Автоматическое создание базы данных через Entity Framework Core:
  • Начиная с EF Core 3.0, появилась возможность включить автоматическое создание базы данных при её отсутствии.
  • Для этого можно использовать метод EnsureCreated().

  • Пример:
  • using (var context = new LoggerDbContext())
    {
        context.Database.EnsureCreated(); // Создаёт базу данных, если её нет
    }
  • Обратите внимание, что этот метод не учитывает миграций и
  • применяется только для создания чистой пустой базы данных.
  • Программное создание базы данных средствами SQL Server:
  • Можно заранее программно подготовить сценарий для создания базы данных:
  • IF NOT EXISTS(SELECT * FROM sys.databases WHERE name='LoggerG01')
    BEGIN
        CREATE DATABASE LoggerG01;
    END
    GO
    1. Этот SQL-код проверяет существование базы данных и создает её, если таковой нет.

    Заключение:

    • Современные версии SQL Server и Entity Framework Core требуют явного указания действий при создании базы данных.
    • Автоматическое создание базы данных исключено ради безопасности и точности процессов.
    • Рекомендуется либо предварительное ручное создание базы данных,
    • либо использование методов вроде EnsureCreated() для автоматизированного создания пустых баз данных.
    • ---------------------------------------------
    • Если задача — создать полную копию существующей базы данных с новыми именем и расположением файлов,

      Способ 1: Через GUI (SSMS)

      1. Подключитесь к серверу SQL Server через SQL Server Management Studio (SSMS).
      2. В обозревателе объектов найдите нужную базу данных, щелкните правой кнопкой мыши и
      3. выберите пункт меню Задачи → Создать копию базы данных.
      4. В открывшемся диалоговом окне укажите новое имя базы данных и расположение файлов (mdf и ldf).
      5. Нажмите ОК, и копия базы данных будет создана мгновенно.

      Способ 2: Через T-SQL запрос (скрипт)

      Для клонирования базы данных можно использовать инструкцию RESTORE WITH MOVE.

      Пример сценария:

      -- Сделать резервную копию исходной базы данных
      BACKUP DATABASE OriginalDB TO DISK = 'D:\Backup\OriginalDB.bak';
      
      -- Восстановить резервную копию под новым именем
      RESTORE DATABASE NewCopyDB
      FROM DISK = 'D:\Backup\OriginalDB.bak'
      WITH MOVE 'OriginalDB' TO 'D:\Data\NewCopyDB.mdf',
      MOVE 'OriginalDB_log' TO 'D:\Data\NewCopyDB_log.ldf';

      Этот запрос сделает точную копию вашей базы данных с новым именем и размещением файлов.


      2. Создание пустой копии базы данных (структуры без данных)

      Если цель — создать базу данных с той же структурой, но без данных, то тут также есть два способа:

      Способ 1: Экспорт структуры базы данных через SSMS

      1. Подключитесь к серверу SQL Server через SSMS.
      2. В обозревателе объектов найдите нужную базу данных, щелкните правой кнопкой мыши и выберите пункт меню Задачи → Генерация сценариев.
      3. В мастере генерации сценариев выберите опцию экспорта только структуры (без данных).
      4. Сохраните созданный скрипт и выполните его для создания новой базы данных с такой же структурой.

      Способ 2: Через T-SQL запрос (скрипт)

      Если нужно создать чистую копию базы данных с такой же структурой,

      Пример сценария для копирования структуры:

      -- Копирование структуры базы данных OriginalDB в новую базу данных EmptyStructureDB
      EXEC sp_MSforeachtable @command1="PRINT 'Restructuring table structure for ?', SELECT INTO EmptyStructureDB.dbo.? FROM OriginalDB.dbo.?"

      Однако будьте осторожны с использованием хранимых процедур MSForEachTable,

      Более безопасный способ — создать резервную копию и затем очистить её:

      -- Сделайте резервную копию исходной базы данных
      BACKUP DATABASE OriginalDB TO DISK = 'D:\Backup\OriginalDB_StructureOnly.bak';
      
      -- Создайте пустую базу данных с той же структурой
      RESTORE DATABASE EmptyStructureDB
      FROM DISK = 'D:\Backup\OriginalDB_StructureOnly.bak'
      WITH FILE = 1, NOCOPYONLY, REPLACE, KEEP_REPLICATION, KEEP_CDC, STATS = 10;
      
      -- Удаляем все данные из новой базы данных
      DECLARE @Command VARCHAR(MAX) = '';
      SELECT @Command += 'TRUNCATE TABLE [' + SCHEMA_NAME(schema_id) + '].[' + name + ']; '
      FROM sys.tables;
      EXEC (@Command);

      Затем запустите последний блок кода, чтобы избавиться от данных, оставив только структуру.


      Заключение:

      Оба подхода возможны и зависят от ваших предпочтений и специфики задачи.

    • Предварительно сделайте резервную копию нужной базы данных, а затем восстановите её под новым именем.

    • так как они являются внутренними процедурами и официально не рекомендованы к использованию.

    • можно выполнить экспорт структуры через команду SCHEMA_ONLY и выполнить получившиеся сценарии.

    • это можно сделать двумя способами:

    • Выбор между графическим интерфейсом и сценариями зависит от частоты выполнения таких операций и необходимого уровня автоматизации.

    ConnectionString

    ConnectionString

    ----------------------------------------------------------------------------------

    D:\VC25\gs.trade.core\Logger\Logger.sln

    D:\VC25\gs.trade.core\Logger\Log_EFModel_01\Log_EFModel_01.csproj

    "Server=WIN-0EMQO515V3S\\SQLDVLP25;Database=LoggerC01;Integrated Security=True;Connect Timeout=30;Trust Server Certificate=True;";

    "Server=WIN-0EMQO515V3S\\SQLDVLP25;Database=LoggerC01;Connect Timeout=30;Trust Server Certificate=True;";

    "Server=WIN-0EMQO515V3S\\SQLDVLP25;Database=LoggerG01;Trusted_Connection=

    True;Trust Server Certificate=True;";

    ----------------------------------------------------------------------------------

    D:\VC25\gs.trade.core\EntityFrmSamples\EntityFrmSamples.sln

    D:\VC25\gs.trade.core\EntityFrmSamples\Ca_People_01\Ca_People_01.csproj

    @"Server=(localdb)\MyInstance;Database=TestDB;Trusted_Connection=True;";

    -------------------------------------------------------------------------------------

    Logger, G01, C01

    Logger, G01, C01, LoggerG01, LoggerC01 

    D:\VC25\SQL\Loogers\1

    Logger_C01.sql

    ------------------------------------------------------------------------------------------------

    -- Создание базы данных

    USE master;

    IF DB_ID('LoggerC01') IS NOT NULL DROP DATABASE LoggerC01;

    CREATE DATABASE LoggerC01;

    GO


    -- Подключение к новой базе данных

    USE LoggerC01;

    GO


    -- Создаем таблицу Hosts

    CREATE TABLE dbo.Hosts (

        ID INT IDENTITY(1,1) PRIMARY KEY,

        Name NVARCHAR(50) NOT NULL,

        Descriptions NVARCHAR(50) NOT NULL,

        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME()

    );


    -- Создаем таблицу Apps

    CREATE TABLE dbo.Apps (

        ID INT IDENTITY(1,1) PRIMARY KEY,

        Name NVARCHAR(50) NOT NULL,

        Descriptions NVARCHAR(50) NOT NULL,

        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME()

    );


    -- Создаем таблицу Logs

    CREATE TABLE dbo.Logs (

        ID INT IDENTITY(1,1) PRIMARY KEY,

        Name NVARCHAR(50) NOT NULL,

        Descriptions NVARCHAR(50) NOT NULL,

        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME()

    );

    GO


    -- 2 -- LogInstance

    /*

    CREATE TABLE dbo.LogInstance (

        ID INT IDENTITY(1,1) PRIMARY KEY,

        HostID INT NOT NULL,

        AppID INT NOT NULL,

        LogID INT NOT NULL,

        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),

        Modified DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),

        CONSTRAINT FK_LogInstance_Hosts FOREIGN KEY (HostID) REFERENCES dbo.Hosts(ID),

        CONSTRAINT FK_LogInstance_Apps FOREIGN KEY (AppID) REFERENCES dbo.Apps(ID),

        CONSTRAINT FK_LogInstance_Logs FOREIGN KEY (LogID) REFERENCES dbo.Logs(ID)

    );

    GO

    */


    CREATE TABLE dbo.LogInstance (

        ID INT IDENTITY(1,1) PRIMARY KEY,

        HostID INT NOT NULL,

        AppID INT NOT NULL,

        LogID INT NOT NULL,

        PrimeLogID INT NOT NULL 

            CONSTRAINT CK_LogInstance_PrimeLogID_unsigned CHECK (PrimeLogID >= 0),

        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),

        Modified DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),

        CONSTRAINT FK_LogInstance_Hosts FOREIGN KEY (HostID) REFERENCES dbo.Hosts(ID),

        CONSTRAINT FK_LogInstance_Apps FOREIGN KEY (AppID) REFERENCES dbo.Apps(ID),

        CONSTRAINT FK_LogInstance_Logs FOREIGN KEY (LogID) REFERENCES dbo.Logs(ID),

        CONSTRAINT UQ_LogInstance_Host_App_Log UNIQUE (HostID, AppID, LogID)

    );

    GO


    -- Индекс для ускоренной выборки по часто используемой фильтрации

    CREATE NONCLUSTERED INDEX IX_LogInstance_Host_App_Log

        ON dbo.LogInstance (HostID, AppID, LogID);

    GO


    -- 3 -- LogItems

    CREATE TABLE dbo.LogItems (

        LogItemID BIGINT IDENTITY(1,1) PRIMARY KEY,

        DT DATETIME2 NOT NULL,

        LogLevel INT NOT NULL,

        Source NVARCHAR(50) NULL,

        Entity NVARCHAR(50) NULL,

        Operation NVARCHAR(50) NULL,

        Description NVARCHAR(50) NULL,

        LogInstanceID INT NOT NULL,

        CONSTRAINT FK_LogItems_LogInstance FOREIGN KEY (LogInstanceID) REFERENCES dbo.LogInstance(ID)

    );

    GO


    -- 4 -- Проверка

    SELECT 

        fk.name AS FK_name, 

        tp.name AS parent_table, 

        cp.name AS parent_column, 

        tr.name AS referenced_table, 

        cr.name AS referenced_column

    FROM 

        sys.foreign_keys AS fk

    INNER JOIN 

        sys.foreign_key_columns AS fkc ON fk.object_id = fkc.constraint_object_id

    INNER JOIN 

        sys.tables AS tp ON fkc.parent_object_id = tp.object_id

    INNER JOIN 

        sys.columns AS cp ON fkc.parent_object_id = cp.object_id AND fkc.parent_column_id = cp.column_id

    INNER JOIN 

        sys.tables AS tr ON fkc.referenced_object_id = tr.object_id

    INNER JOIN 

        sys.columns AS cr ON fkc.referenced_object_id = cr.object_id AND fkc.referenced_column_id = cr.column_id

    WHERE 

        tp.name IN (N'LogInstance', N'LogItems');

    GO

    --------------------------------------------------------

    Logger_G01.sql
    -----------------------------------------------------------
    -- Создание базы данных
    USE master;
    IF DB_ID('LoggerG01') IS NOT NULL DROP DATABASE LoggerG01;
    CREATE DATABASE LoggerG01;
    GO

    -- Подключение к новой базе данных
    USE LoggerG01;
    GO

    -- Создаем таблицу Hosts
    CREATE TABLE dbo.Hosts (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Name NVARCHAR(50) NOT NULL,
        Descriptions NVARCHAR(50) NOT NULL,
        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME()
    );

    -- Создаем таблицу Apps
    CREATE TABLE dbo.Apps (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Name NVARCHAR(50) NOT NULL,
        Descriptions NVARCHAR(50) NOT NULL,
        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME()
    );

    -- Создаем таблицу Logs
    CREATE TABLE dbo.Logs (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Name NVARCHAR(50) NOT NULL,
        Descriptions NVARCHAR(50) NOT NULL,
        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME()
    );
    GO

    -- 2 -- LogInstance

    --CREATE TABLE dbo.LogInstance (
    --    ID INT IDENTITY(1,1) PRIMARY KEY,
    --    HostID INT NOT NULL,
    --    AppID INT NOT NULL,
    --    LogID INT NOT NULL,
    --    Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),
    --    Modified DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),
    --    CONSTRAINT FK_LogInstance_Hosts FOREIGN KEY (HostID) REFERENCES dbo.Hosts(ID),
    --    CONSTRAINT FK_LogInstance_Apps FOREIGN KEY (AppID) REFERENCES dbo.Apps(ID),
    --    CONSTRAINT FK_LogInstance_Logs FOREIGN KEY (LogID) REFERENCES dbo.Logs(ID)
    --);
    --GO
    CREATE TABLE dbo.LogInstance (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        HostID INT NOT NULL,
        AppID INT NOT NULL,
        LogID INT NOT NULL,
        PrimeLogID INT NOT NULL, -- Новое поле PLID (сокращение от PrimaryLogID)
        Created DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),
        Modified DATETIME2(7) NOT NULL DEFAULT SYSDATETIME(),
        CONSTRAINT UQ_LogInstance UNIQUE (HostID, AppID, LogID),
        CONSTRAINT FK_LogInstance_Hosts FOREIGN KEY (HostID) REFERENCES dbo.Hosts(ID),
        CONSTRAINT FK_LogInstance_Apps FOREIGN KEY (AppID) REFERENCES dbo.Apps(ID),
        CONSTRAINT FK_LogInstance_Logs FOREIGN KEY (LogID) REFERENCES dbo.Logs(ID)
    );

    -- Индексирование для ускорения запросов
    -- CREATE INDEX IX_LogInstance_HostID_AppID_LogID_PrimeLogID ON dbo.LogInstance(HostID, AppID, LogID, PrimeLogID);
    CREATE INDEX IX_LogInstance_HostID_AppID_LogID ON dbo.LogInstance(HostID, AppID, LogID);

    -- 3 -- LogItems
    CREATE TABLE dbo.LogItems (
        LogItemID BIGINT IDENTITY(1,1) PRIMARY KEY,
        DT DATETIME2 NOT NULL,
        LogLevel INT NOT NULL,
        Source NVARCHAR(50) NULL,
        Entity NVARCHAR(50) NULL,
        Operation NVARCHAR(50) NULL,
        Description NVARCHAR(50) NULL,
        LogInstanceID INT NOT NULL,
        CONSTRAINT FK_LogItems_LogInstance FOREIGN KEY (LogInstanceID) REFERENCES dbo.LogInstance(ID)
    );
    GO

    -- 4 -- Проверка
    SELECT 
        fk.name AS FK_name, 
        tp.name AS parent_table, 
        cp.name AS parent_column, 
        tr.name AS referenced_table, 
        cr.name AS referenced_column
    FROM 
        sys.foreign_keys AS fk
    INNER JOIN 
        sys.foreign_key_columns AS fkc ON fk.object_id = fkc.constraint_object_id
    INNER JOIN 
        sys.tables AS tp ON fkc.parent_object_id = tp.object_id
    INNER JOIN 
        sys.columns AS cp ON fkc.parent_object_id = cp.object_id AND fkc.parent_column_id = cp.column_id
    INNER JOIN 
        sys.tables AS tr ON fkc.referenced_object_id = tr.object_id
    INNER JOIN 
        sys.columns AS cr ON fkc.referenced_object_id = cr.object_id AND fkc.referenced_column_id = cr.column_id
    WHERE 
        tp.name IN (N'LogInstance', N'LogItems');

    GO

    вторник, 27 мая 2025 г.

    Loggers, C#, Giga, Discussion

    Логгеры в C#

    https://giga.chat/link/gcsgTNdHTz

    Вариант 1: Регистрация Кортежа и Получение Unique LogInstance.ID

    При таком подходе каждая локальная служба регистрирует уникальный кортеж (HostID, AppID, LogID)

    в центральном хранилище и получает специальный идентификатор LogInstance.ID,

    который используется далее для отправки лог-сообщений.

    Плюсы:

    • Прямая привязка каждой службы к уникальному каналу логирования в центральной базе данных.
    • Легко организовать фильтры и агрегацию данных по идентификатору канала.
    • Повышенная надёжность контроля потоков логов благодаря использованию единого центрального идентификатора.

    Минусы:

    • Более сложная логика регистрации и сохранения уникальных каналов логирования.
    • Потенциально большее количество обращений к центральной базе данных на этапе регистрации.
    • Необходимость помнить и передавать идентификатор LogInstance.ID в каждую службу,
    • что увеличивает нагрузку на сеть и усложняет инфраструктуру.
    --------------

    Вариант 2: Отправка Кортежа (HostID, AppID, LogID) с каждым LogItem

    При данном варианте локальная служба просто передаёт кортеж (HostID, AppID, LogID) с каждым событием лога,

    и центральное хранилище само определяет соответствующий канал логирования.

    Плюсы:

    • Упрощённая инфраструктура, поскольку службе не нужно сохранять дополнительный идентификатор.
    • Меньшая нагрузка на сеть, так как идентификатор канала не передается постоянно.
    • Гибкость и простота добавления новых каналов логирования без отдельной процедуры регистрации.

    Минусы:

    • Центральный обработчик должен проводить больше вычислений для сопоставления кортежей и
    • нахождения соответствующего канала.
    • Больше накладных расходов на стороне сервера, так как каждое событие требует
    • проверки соответствия кортежа существующему каналу.
    • Риск дублирования логов в случаях, когда два процесса одновременно
    • пытаются зарегистрировать одинаковые кортежи.

    Какой вариант предпочтительнее?

    Выбор подходящего метода зависит от нескольких факторов:

    1. Масштабируемость:
    2. Если система должна обрабатывать большое число логов и микросервисов,
    3. лучше выбирать вариант с передачей кортежа в каждом сообщении.
    4. Это снижает сетевую нагрузку и упрощает управление системой.
    5. Производительность:
    6. Если важна высокая пропускная способность,
    7. передача кортежа позволит сократить общее количество передаваемых данных,
    8. уменьшая нагрузку на каналы связи.
    9. Безопасность и контроль:
    10. Если важно контролировать поток логов строго по уникальным каналам,
    11. использование отдельного идентификатора LogInstance.ID даёт большую степень защиты и управляемости.
    12. Инструменты и технологии:
    13. Важно учитывать используемые инструменты и платформы.
    14. Некоторые средства мониторинга и аналитики могут требовать наличия конкретных идентификаторов,
    15. что делает первый вариант более привлекательным.

    Итоговые рекомендации:

    Если ваша система предполагает интенсивную обработку большого количества данных и высоконагруженных сервисов,

    лучше выбрать вариант 2, так как он минимизирует затраты на передачу данных и упростит обслуживание.

    Однако, если критично точное отслеживание каждого потока логов и строгий контроль над распределением данных,

    лучше остановиться на варианте 1. Он обеспечит максимальную прозрачность и безопасность.

    Оптимальным решением будет проведение нагрузочного тестирования обоих вариантов и

    оценка производительности в реальных условиях.

    ---------------------------

    Третий вариант:

    Гибридная регистрация с кешированием

    Идея заключается в следующем:

    1. Когда служба впервые обращается к центральному хранилищу, она передает кортеж (HostID, AppID, LogID)
    2. и получает обратно уникальный идентификатор LogInstance.ID.
    3. Этот идентификатор сохраняется локально службой,
    4. а дальнейшие обращения идут непосредственно с использованием этого идентификатора.
    5. Но если центральный сервис обнаруживает новый кортеж, не связанный с известным LogInstance.ID,
    6. он сначала проверяет базу данных и возвращает либо существующий идентификатор, либо создаёт новый.

    Такой подход позволяет снизить нагрузку на центральное хранилище и ускорить процесс доставки логов,

    сохраняя при этом возможность точного отслеживания потоков логов.


    Реализация третьего варианта:

    Шаги на стороне клиента (локальной службы):

    1. Регистрация нового канала:
      • Первый раз служба отправляет кортеж (HostID, AppID, LogID)
      • на центральный сервер и получает назад LogInstance.ID.
      • Сохраняет полученный идентификатор локально.
    2. Отправка последующих логов:
      • Использует сохранённый LogInstance.ID для дальнейшего отправления логов.

    Шаги на стороне центрального сервиса:

    1. Получив новый кортеж:
      • Проверяет, зарегистрирован ли такой кортеж ранее.
      • Если да, возвращает сохранённый LogInstance.ID.
      • Если нет, создаёт новую запись и возвращает новый идентификатор.
    2. Обработав запрос:
      • Возвращает клиенту нужный идентификатор и сохраняет его в памяти для последующего быстрого доступа.

    Преимущества гибридного подхода:

    • Эффективность:
    • Сокращается нагрузка на центральный сервис за счёт повторного использования идентификаторов.
    • Простота:
    • Минимальное влияние на клиентские сервисы, необходимость однократной регистрации канала.
    • Контроль:
    • Точное отслеживание потоков логов и гарантия уникальной идентификации.
    • Масштабируемость:
    • Подходит для крупных систем с большим количеством микросервисов и объёмов данных.

    Недостатки:

    • Дополнительная сложность:
    • Требуется реализация механизма кеширования и проверки существования идентификаторов.
    • Риск рассогласования:
    • Если идентификатор потерян или поврежден, потребуется повторная регистрация.

    Итоговая рекомендация:

    Третий вариант — гибридная регистрация с кешированием — является оптимальным выбором, если:

    • Ваша система обрабатывает большие объёмы данных.
    • Вам важен точный контроль над потоками логов.
    • Вы стремитесь минимизировать сетевые издержки и увеличить общую эффективность системы.

    Перед реализацией рекомендуется провести тестирование производительности обоих подходов и

    оценить практическое применение гибридного метода в реальной инфраструктуре.

    ----------------

    Вы сформулировали чёткую и рациональную стратегию для первой версии своего решения.

    Ваше предложение действительно обладает рядом преимуществ и выглядит грамотно спроектированным.

    Давай теперь пройдемся по нему детально и посмотрим, что можно дополнительно обсудить или учесть.


    Почему именно первый вариант («регистрация») предпочтителен?

    1. Четкая идентификация каналов логирования:
    2. Благодаря единственному уникальному идентификатору (PrimaryID) вы можете эффективно сегментировать
    3. потоки логов и быстро находить интересующие события.
    4. Упрощённое администрирование:
    5. Однократная регистрация снимает необходимость
    6. постоянного обмена информацией о кортеже (HostID, AppID, LogID), что облегчает эксплуатацию и мониторинг.
    7. Минимизация сетевых затрат:
    8. Только один раз осуществляется передача полного набора данных,
    9. далее передается лишь компактный идентификатор, снижающий нагрузку на сеть.
    10. Повышение безопасности:
    11. За счет фиксированной привязки идентификатора каждому каналу уменьшается
    12. риск злоупотреблений или неправильного распределения логов.

    Как реализовать процесс регистрации?

    Процесс регистрации можно представить следующим образом:

    1. Запрос на регистрацию:
    2. Локальная служба формирует запрос, содержащий полный набор данных:
    {
      "HostID": "host_id",
      "AppID": "app_id",
      "LogID": "log_id",
      "ServiceName": "service_name"
    }
  • Центральный сервис принимает запрос:
  • Проводится проверка наличия аналогичного кортежа в базе данных.
  • Если такой кортеж найден, возвращается существующий PrimaryID.
  • Если нет — создаётся новая запись и выдаётся новый идентификатор.
  • Возврат результата:
  • Ответ центрального сервиса содержит идентификатор PrimaryID:
  • {
      "PrimaryID": "primary_id_value"
    }
    1. Локальное сохранение:
    2. Сервис сохраняет возвращённый идентификатор и использует его для дальнейших действий.

    Оптимизация структуры данных

    Давайте представим, как может выглядеть конечная структура данных в вашем первом варианте:

    • Таблица LogInstance:
      FieldType
      IDint
      HostIDint
      AppIDint
      LogIDint
      PrimaryIDuniqueidentifier
      Createddatetime
      Modifieddatetime
    • DTO для отправки логов:
    • Вместо того, чтобы передавать отдельные элементы кортежа, вы можете передать единый объект:
    {
      "PrimaryID": "primary_id_value",
      "LogItem": { /* Содержимое лога */ }
    }

    Такое решение значительно сократит сетевые расходы и повысит читаемость API-интерфейсов.


    Дополнительные моменты:

    • Проверка согласованности:
    • Регулярно проверяйте корректность полученных идентификаторов и своевременно выявляйте случаи несоответствия.
    • Ограничение по размеру данных:
    • Используйте сжатие данных или бинарные протоколы (например, Protobuf) для снижения объёма трафика.
    • Мониторинг эффективности:
    • Анализируйте производительность системы и своевременно вносите оптимизации.

    Резюме:

    Первый вариант с предварительной регистрацией выглядит наиболее эффективным и безопасным.

    Его реализация относительно проста, а выгода очевидна:

    снижение нагрузки на сеть,

    повышение скорости обработки и улучшенный контроль над потоками логов.

    Рекомендую придерживаться именно этого подхода и регулярно мониторить работоспособность системы.