970d0a5cb3
Replace SiteDataConnectionAssignment join table with a direct SiteId FK on DataConnection, simplifying the data model, repositories, UI, CLI, and deployment service.
185 lines
7.5 KiB
C#
185 lines
7.5 KiB
C#
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
#nullable disable
|
|
|
|
namespace ScadaLink.ConfigurationDatabase.Migrations
|
|
{
|
|
/// <inheritdoc />
|
|
public partial class AddSiteIdToDataConnections : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
// Step 1: Drop old unique index on Name (allows duplicate names across sites)
|
|
migrationBuilder.DropIndex(
|
|
name: "IX_DataConnections_Name",
|
|
table: "DataConnections");
|
|
|
|
// Step 2: Add nullable SiteId column
|
|
migrationBuilder.AddColumn<int>(
|
|
name: "SiteId",
|
|
table: "DataConnections",
|
|
type: "int",
|
|
nullable: true);
|
|
|
|
// Step 3: Migrate data from SiteDataConnectionAssignments
|
|
migrationBuilder.Sql(@"
|
|
-- Phase A: Assign the first site to each existing DataConnection
|
|
UPDATE dc
|
|
SET dc.SiteId = a.SiteId
|
|
FROM DataConnections dc
|
|
INNER JOIN (
|
|
SELECT DataConnectionId, MIN(SiteId) AS SiteId
|
|
FROM SiteDataConnectionAssignments
|
|
GROUP BY DataConnectionId
|
|
) a ON dc.Id = a.DataConnectionId
|
|
WHERE dc.SiteId IS NULL;
|
|
|
|
-- Phase B: For connections assigned to additional sites, create copies
|
|
-- and update InstanceConnectionBindings to point to the new copy
|
|
DECLARE @AssignSiteId INT, @AssignConnId INT, @NewConnId INT;
|
|
DECLARE @OrigName NVARCHAR(200), @OrigProtocol NVARCHAR(50), @OrigConfig NVARCHAR(4000);
|
|
|
|
DECLARE assignment_cursor CURSOR FOR
|
|
SELECT a.SiteId, a.DataConnectionId
|
|
FROM SiteDataConnectionAssignments a
|
|
INNER JOIN DataConnections dc ON a.DataConnectionId = dc.Id
|
|
WHERE dc.SiteId <> a.SiteId;
|
|
|
|
OPEN assignment_cursor;
|
|
FETCH NEXT FROM assignment_cursor INTO @AssignSiteId, @AssignConnId;
|
|
|
|
WHILE @@FETCH_STATUS = 0
|
|
BEGIN
|
|
SELECT @OrigName = Name, @OrigProtocol = Protocol, @OrigConfig = Configuration
|
|
FROM DataConnections WHERE Id = @AssignConnId;
|
|
|
|
INSERT INTO DataConnections (SiteId, Name, Protocol, Configuration)
|
|
VALUES (@AssignSiteId, @OrigName, @OrigProtocol, @OrigConfig);
|
|
|
|
SET @NewConnId = SCOPE_IDENTITY();
|
|
|
|
-- Update bindings for instances on this site to point to the new connection
|
|
UPDATE icb
|
|
SET icb.DataConnectionId = @NewConnId
|
|
FROM InstanceConnectionBindings icb
|
|
INNER JOIN Instances i ON icb.InstanceId = i.Id
|
|
WHERE icb.DataConnectionId = @AssignConnId
|
|
AND i.SiteId = @AssignSiteId;
|
|
|
|
FETCH NEXT FROM assignment_cursor INTO @AssignSiteId, @AssignConnId;
|
|
END
|
|
|
|
CLOSE assignment_cursor;
|
|
DEALLOCATE assignment_cursor;
|
|
|
|
-- Phase C: Handle any DataConnections not assigned to any site
|
|
-- (assign to the first site as a fallback)
|
|
UPDATE dc
|
|
SET dc.SiteId = (SELECT TOP 1 Id FROM Sites ORDER BY Id)
|
|
FROM DataConnections dc
|
|
WHERE dc.SiteId IS NULL;
|
|
");
|
|
|
|
// Step 4: Make SiteId non-nullable
|
|
migrationBuilder.AlterColumn<int>(
|
|
name: "SiteId",
|
|
table: "DataConnections",
|
|
type: "int",
|
|
nullable: false,
|
|
defaultValue: 0,
|
|
oldClrType: typeof(int),
|
|
oldType: "int",
|
|
oldNullable: true);
|
|
|
|
// Step 5: Add composite unique index and FK
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_DataConnections_SiteId_Name",
|
|
table: "DataConnections",
|
|
columns: new[] { "SiteId", "Name" },
|
|
unique: true);
|
|
|
|
migrationBuilder.AddForeignKey(
|
|
name: "FK_DataConnections_Sites_SiteId",
|
|
table: "DataConnections",
|
|
column: "SiteId",
|
|
principalTable: "Sites",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Restrict);
|
|
|
|
// Step 6: Drop SiteDataConnectionAssignments table
|
|
migrationBuilder.DropTable(
|
|
name: "SiteDataConnectionAssignments");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
// Recreate SiteDataConnectionAssignments table
|
|
migrationBuilder.CreateTable(
|
|
name: "SiteDataConnectionAssignments",
|
|
columns: table => new
|
|
{
|
|
Id = table.Column<int>(type: "int", nullable: false)
|
|
.Annotation("SqlServer:Identity", "1, 1"),
|
|
DataConnectionId = table.Column<int>(type: "int", nullable: false),
|
|
SiteId = table.Column<int>(type: "int", nullable: false)
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("PK_SiteDataConnectionAssignments", x => x.Id);
|
|
table.ForeignKey(
|
|
name: "FK_SiteDataConnectionAssignments_DataConnections_DataConnectionId",
|
|
column: x => x.DataConnectionId,
|
|
principalTable: "DataConnections",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "FK_SiteDataConnectionAssignments_Sites_SiteId",
|
|
column: x => x.SiteId,
|
|
principalTable: "Sites",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
});
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_SiteDataConnectionAssignments_DataConnectionId",
|
|
table: "SiteDataConnectionAssignments",
|
|
column: "DataConnectionId");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_SiteDataConnectionAssignments_SiteId_DataConnectionId",
|
|
table: "SiteDataConnectionAssignments",
|
|
columns: new[] { "SiteId", "DataConnectionId" },
|
|
unique: true);
|
|
|
|
// Migrate data back
|
|
migrationBuilder.Sql(@"
|
|
INSERT INTO SiteDataConnectionAssignments (SiteId, DataConnectionId)
|
|
SELECT SiteId, Id FROM DataConnections;
|
|
");
|
|
|
|
// Remove FK and composite index
|
|
migrationBuilder.DropForeignKey(
|
|
name: "FK_DataConnections_Sites_SiteId",
|
|
table: "DataConnections");
|
|
|
|
migrationBuilder.DropIndex(
|
|
name: "IX_DataConnections_SiteId_Name",
|
|
table: "DataConnections");
|
|
|
|
// Restore unique index on Name
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_DataConnections_Name",
|
|
table: "DataConnections",
|
|
column: "Name",
|
|
unique: true);
|
|
|
|
// Drop SiteId column
|
|
migrationBuilder.DropColumn(
|
|
name: "SiteId",
|
|
table: "DataConnections");
|
|
}
|
|
}
|
|
}
|