Files
scadalink-design/src/ScadaLink.ConfigurationDatabase/Migrations/ScadaLinkDbContextModelSnapshot.cs
Joseph Doherty d9c99242a3 feat(configdb): add AuditLog migration with monthly partitioning and DB roles (#23)
Bundle C of the #23 M1 foundation. Creates the centralized AuditLog table
with the partition function, partition scheme, partition-aligned
non-clustered indexes, and the two access-control roles documented in
alog.md §4.

Schema:
- pf_AuditLog_Month: RANGE RIGHT, 24 monthly boundaries (Jan 2026 – Dec 2027).
- ps_AuditLog_Month: ALL TO ([PRIMARY]) — dev/test parity.
- dbo.AuditLog: created via raw SQL ON ps_AuditLog_Month(OccurredAtUtc).
  Composite clustered PK {EventId, OccurredAtUtc} (partition column must be
  part of the clustered key). 22 columns matching the EF AuditEvent model.
- 5 reconciliation/query non-clustered indexes from alog.md §4
  (Channel_Status_Occurred, CorrelationId filtered, OccurredAtUtc,
  Site_Occurred, Target_Occurred filtered) — all partition-aligned.
- UX_AuditLog_EventId: non-aligned UNIQUE on EventId alone (preserves
  InsertIfNotExistsAsync idempotency from M1-T8). Non-aligned because
  partition-aligned unique indexes require the partition column in the key,
  which would weaken to composite uniqueness; the purge story (M2/M3)
  rebuilds this index around partition switches.

Access control:
- scadalink_audit_writer: GRANT INSERT + GRANT SELECT, DENY UPDATE + DENY DELETE
  on AuditLog. The explicit DENY guarantees later db_datawriter membership
  cannot quietly re-enable mutation.
- scadalink_audit_purger: GRANT SELECT on AuditLog, GRANT ALTER on SCHEMA::dbo
  (enables ALTER PARTITION FUNCTION SWITCH and SWITCH PARTITION).

Both role definitions are idempotent (IF DATABASE_PRINCIPAL_ID IS NULL).
Down() drops in reverse dependency order with IF EXISTS guards.

Integration tests (tests/ScadaLink.ConfigurationDatabase.Tests/Migrations/):
- MsSqlMigrationFixture: connects to the running infra/mssql container (or
  the SCADALINK_MSSQL_TEST_CONN override), creates a unique per-fixture
  database, applies the migrations, drops the DB on dispose. Marks itself
  Available=false when MSSQL is unreachable so tests early-return cleanly
  on CI without the dev container.
- AddAuditLogTableMigrationTests: 8 tests covering table existence,
  partition function/scheme, partition-aligned PK, the 5 named indexes,
  both roles' grants, and a smoke test that a writer-role user receives
  SqlException with "permission" on UPDATE AuditLog.

ConfigurationDatabase tests: 142 passing -> 150 passing (8 new integration
tests). Full solution builds clean.

Package: tests project locally overrides Microsoft.Data.SqlClient to 6.1.1
(EF SqlServer 10.0.7 needs >= 6.1.1; central package version is pinned at
6.0.2 for the production ExternalSystemGateway).
2026-05-20 10:25:25 -04:00

1551 lines
56 KiB
C#

// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using ScadaLink.ConfigurationDatabase;
#nullable disable
namespace ScadaLink.ConfigurationDatabase.Migrations
{
[DbContext(typeof(ScadaLinkDbContext))]
partial class ScadaLinkDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("FriendlyName")
.HasColumnType("nvarchar(max)");
b.Property<string>("Xml")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("DataProtectionKeys");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Audit.AuditEvent", b =>
{
b.Property<Guid>("EventId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("OccurredAtUtc")
.HasColumnType("datetime2");
b.Property<string>("Actor")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<string>("Channel")
.IsRequired()
.HasMaxLength(32)
.IsUnicode(false)
.HasColumnType("varchar(32)");
b.Property<Guid?>("CorrelationId")
.HasColumnType("uniqueidentifier");
b.Property<int?>("DurationMs")
.HasColumnType("int");
b.Property<string>("ErrorDetail")
.HasColumnType("nvarchar(max)");
b.Property<string>("ErrorMessage")
.HasMaxLength(1024)
.HasColumnType("nvarchar(1024)");
b.Property<string>("Extra")
.HasColumnType("nvarchar(max)");
b.Property<string>("ForwardState")
.HasMaxLength(32)
.IsUnicode(false)
.HasColumnType("varchar(32)");
b.Property<int?>("HttpStatus")
.HasColumnType("int");
b.Property<DateTime?>("IngestedAtUtc")
.HasColumnType("datetime2");
b.Property<string>("Kind")
.IsRequired()
.HasMaxLength(32)
.IsUnicode(false)
.HasColumnType("varchar(32)");
b.Property<bool>("PayloadTruncated")
.HasColumnType("bit");
b.Property<string>("RequestSummary")
.HasColumnType("nvarchar(max)");
b.Property<string>("ResponseSummary")
.HasColumnType("nvarchar(max)");
b.Property<string>("SourceInstanceId")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<string>("SourceScript")
.HasMaxLength(128)
.IsUnicode(false)
.HasColumnType("varchar(128)");
b.Property<string>("SourceSiteId")
.HasMaxLength(64)
.IsUnicode(false)
.HasColumnType("varchar(64)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(32)
.IsUnicode(false)
.HasColumnType("varchar(32)");
b.Property<string>("Target")
.HasMaxLength(256)
.IsUnicode(false)
.HasColumnType("varchar(256)");
b.HasKey("EventId", "OccurredAtUtc");
b.HasIndex("CorrelationId")
.HasDatabaseName("IX_AuditLog_CorrelationId")
.HasFilter("[CorrelationId] IS NOT NULL");
b.HasIndex("EventId")
.IsUnique()
.HasDatabaseName("UX_AuditLog_EventId");
b.HasIndex("OccurredAtUtc")
.IsDescending()
.HasDatabaseName("IX_AuditLog_OccurredAtUtc");
b.HasIndex("SourceSiteId", "OccurredAtUtc")
.IsDescending(false, true)
.HasDatabaseName("IX_AuditLog_Site_Occurred");
b.HasIndex("Target", "OccurredAtUtc")
.IsDescending(false, true)
.HasDatabaseName("IX_AuditLog_Target_Occurred")
.HasFilter("[Target] IS NOT NULL");
b.HasIndex("Channel", "Status", "OccurredAtUtc")
.IsDescending(false, false, true)
.HasDatabaseName("IX_AuditLog_Channel_Status_Occurred");
b.ToTable("AuditLog", (string)null);
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Audit.AuditLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("AfterStateJson")
.HasColumnType("nvarchar(max)");
b.Property<string>("EntityId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("EntityName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("EntityType")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("datetimeoffset");
b.Property<string>("User")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("EntityId");
b.HasIndex("EntityType");
b.HasIndex("Timestamp");
b.HasIndex("User");
b.ToTable("AuditLogEntries");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeployedConfigSnapshot", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ConfigurationJson")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTimeOffset>("DeployedAt")
.HasColumnType("datetimeoffset");
b.Property<string>("DeploymentId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int>("InstanceId")
.HasColumnType("int");
b.Property<string>("RevisionHash")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.HasIndex("DeploymentId");
b.HasIndex("InstanceId")
.IsUnique();
b.ToTable("DeployedConfigSnapshots");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTimeOffset?>("CompletedAt")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset>("DeployedAt")
.HasColumnType("datetimeoffset");
b.Property<string>("DeployedBy")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("DeploymentId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("ErrorMessage")
.HasColumnType("nvarchar(max)");
b.Property<int>("InstanceId")
.HasColumnType("int");
b.Property<string>("RevisionHash")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<byte[]>("RowVersion")
.IsConcurrencyToken()
.IsRequired()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("rowversion");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.HasIndex("DeployedAt");
b.HasIndex("DeploymentId")
.IsUnique();
b.HasIndex("InstanceId");
b.ToTable("DeploymentRecords");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.SystemArtifactDeploymentRecord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ArtifactType")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<DateTimeOffset>("DeployedAt")
.HasColumnType("datetimeoffset");
b.Property<string>("DeployedBy")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("PerSiteStatus")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("DeployedAt");
b.ToTable("SystemArtifactDeploymentRecords");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.DatabaseConnectionDefinition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ConnectionString")
.IsRequired()
.HasMaxLength(8000)
.HasColumnType("nvarchar(max)");
b.Property<int>("MaxRetries")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<TimeSpan>("RetryDelay")
.HasColumnType("time");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("DatabaseConnectionDefinitions");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemDefinition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("AuthConfiguration")
.HasMaxLength(8000)
.HasColumnType("nvarchar(max)");
b.Property<string>("AuthType")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("EndpointUrl")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int>("MaxRetries")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<TimeSpan>("RetryDelay")
.HasColumnType("time");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ExternalSystemDefinitions");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemMethod", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ExternalSystemDefinitionId")
.HasColumnType("int");
b.Property<string>("HttpMethod")
.IsRequired()
.HasMaxLength(10)
.HasColumnType("nvarchar(10)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ParameterDefinitions")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("Path")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<string>("ReturnDefinition")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("ExternalSystemDefinitionId", "Name")
.IsUnique();
b.ToTable("ExternalSystemMethods");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.InboundApi.ApiKey", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<bool>("IsEnabled")
.HasColumnType("bit");
b.Property<string>("KeyHash")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("KeyHash")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiKeys");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.InboundApi.ApiMethod", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ApprovedApiKeyIds")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ParameterDefinitions")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("ReturnDefinition")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("Script")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("TimeoutSeconds")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("ApiMethods");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Area", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int?>("ParentAreaId")
.HasColumnType("int");
b.Property<int>("SiteId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ParentAreaId");
b.HasIndex("SiteId", "ParentAreaId", "Name")
.IsUnique()
.HasFilter("[ParentAreaId] IS NOT NULL");
b.ToTable("Areas");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Instance", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int?>("AreaId")
.HasColumnType("int");
b.Property<int>("SiteId")
.HasColumnType("int");
b.Property<string>("State")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<int>("TemplateId")
.HasColumnType("int");
b.Property<string>("UniqueName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.HasIndex("AreaId");
b.HasIndex("TemplateId");
b.HasIndex("SiteId", "UniqueName")
.IsUnique();
b.ToTable("Instances");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceAlarmOverride", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("AlarmCanonicalName")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<int>("InstanceId")
.HasColumnType("int");
b.Property<int?>("PriorityLevelOverride")
.HasColumnType("int");
b.Property<string>("TriggerConfigurationOverride")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("InstanceId", "AlarmCanonicalName")
.IsUnique();
b.ToTable("InstanceAlarmOverrides");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceAttributeOverride", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("AttributeName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("InstanceId")
.HasColumnType("int");
b.Property<string>("OverrideValue")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("InstanceId", "AttributeName")
.IsUnique();
b.ToTable("InstanceAttributeOverrides");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceConnectionBinding", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("AttributeName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("DataConnectionId")
.HasColumnType("int");
b.Property<int>("InstanceId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("DataConnectionId");
b.HasIndex("InstanceId", "AttributeName")
.IsUnique();
b.ToTable("InstanceConnectionBindings");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.Notification", b =>
{
b.Property<string>("NotificationId")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("Body")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset?>("DeliveredAt")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset?>("LastAttemptAt")
.HasColumnType("datetimeoffset");
b.Property<string>("LastError")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("ListName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTimeOffset?>("NextAttemptAt")
.HasColumnType("datetimeoffset");
b.Property<string>("ResolvedTargets")
.HasColumnType("nvarchar(max)");
b.Property<int>("RetryCount")
.HasColumnType("int");
b.Property<DateTimeOffset>("SiteEnqueuedAt")
.HasColumnType("datetimeoffset");
b.Property<string>("SourceInstanceId")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("SourceScript")
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("SourceSiteId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("Subject")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("TypeData")
.HasColumnType("nvarchar(max)");
b.HasKey("NotificationId");
b.HasIndex("SourceSiteId", "CreatedAt");
b.HasIndex("Status", "NextAttemptAt");
b.ToTable("Notifications");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationList", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("NotificationLists");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationRecipient", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("EmailAddress")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("NotificationListId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("NotificationListId");
b.ToTable("NotificationRecipients");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.SmtpConfiguration", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("AuthType")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<int>("ConnectionTimeoutSeconds")
.HasColumnType("int");
b.Property<string>("Credentials")
.HasMaxLength(8000)
.HasColumnType("nvarchar(max)");
b.Property<string>("FromAddress")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("Host")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<int>("MaxConcurrentConnections")
.HasColumnType("int");
b.Property<int>("MaxRetries")
.HasColumnType("int");
b.Property<int>("Port")
.HasColumnType("int");
b.Property<TimeSpan>("RetryDelay")
.HasColumnType("time");
b.Property<string>("TlsMode")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.ToTable("SmtpConfigurations");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Scripts.SharedScript", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Code")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ParameterDefinitions")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("ReturnDefinition")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("SharedScripts");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Security.LdapGroupMapping", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("LdapGroupName")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.HasIndex("LdapGroupName")
.IsUnique();
b.ToTable("LdapGroupMappings");
b.HasData(
new
{
Id = 1,
LdapGroupName = "SCADA-Admins",
Role = "Admin"
},
new
{
Id = 2,
LdapGroupName = "SCADA-Designers",
Role = "Design"
},
new
{
Id = 3,
LdapGroupName = "SCADA-Deploy-All",
Role = "Deployment"
},
new
{
Id = 4,
LdapGroupName = "SCADA-Deploy-SiteA",
Role = "Deployment"
});
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Security.SiteScopeRule", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("LdapGroupMappingId")
.HasColumnType("int");
b.Property<int>("SiteId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("SiteId");
b.HasIndex("LdapGroupMappingId", "SiteId")
.IsUnique();
b.ToTable("SiteScopeRules");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.DataConnection", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("BackupConfiguration")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<int>("FailoverRetryCount")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(3);
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("PrimaryConfiguration")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("Protocol")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<int>("SiteId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("SiteId", "Name")
.IsUnique();
b.ToTable("DataConnections");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.Site", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<string>("GrpcNodeAAddress")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("GrpcNodeBAddress")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("NodeAAddress")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("NodeBAddress")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("SiteIdentifier")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.HasIndex("SiteIdentifier")
.IsUnique();
b.ToTable("Sites");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.Template", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<int?>("FolderId")
.HasColumnType("int");
b.Property<bool>("IsDerived")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int?>("OwnerCompositionId")
.HasColumnType("int");
b.Property<int?>("ParentTemplateId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("FolderId");
b.HasIndex("Name")
.IsUnique()
.HasFilter("[IsDerived] = 0");
b.HasIndex("ParentTemplateId");
b.ToTable("Templates");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAlarm", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<bool>("IsInherited")
.HasColumnType("bit");
b.Property<bool>("IsLocked")
.HasColumnType("bit");
b.Property<bool>("LockedInDerived")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int?>("OnTriggerScriptId")
.HasColumnType("int");
b.Property<int>("PriorityLevel")
.HasColumnType("int");
b.Property<int>("TemplateId")
.HasColumnType("int");
b.Property<string>("TriggerConfiguration")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("TriggerType")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.HasIndex("TemplateId", "Name")
.IsUnique();
b.ToTable("TemplateAlarms");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAttribute", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("DataSourceReference")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("DataType")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("Description")
.HasMaxLength(2000)
.HasColumnType("nvarchar(2000)");
b.Property<bool>("IsInherited")
.HasColumnType("bit");
b.Property<bool>("IsLocked")
.HasColumnType("bit");
b.Property<bool>("LockedInDerived")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("TemplateId")
.HasColumnType("int");
b.Property<string>("Value")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.HasKey("Id");
b.HasIndex("TemplateId", "Name")
.IsUnique();
b.ToTable("TemplateAttributes");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateComposition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ComposedTemplateId")
.HasColumnType("int");
b.Property<string>("InstanceName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("TemplateId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ComposedTemplateId");
b.HasIndex("TemplateId", "InstanceName")
.IsUnique();
b.ToTable("TemplateCompositions");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateFolder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int?>("ParentFolderId")
.HasColumnType("int");
b.Property<int>("SortOrder")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ParentFolderId", "Name")
.IsUnique()
.HasFilter("[ParentFolderId] IS NOT NULL");
b.ToTable("TemplateFolders");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateScript", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Code")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsInherited")
.HasColumnType("bit");
b.Property<bool>("IsLocked")
.HasColumnType("bit");
b.Property<bool>("LockedInDerived")
.HasColumnType("bit");
b.Property<TimeSpan?>("MinTimeBetweenRuns")
.HasColumnType("time");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<string>("ParameterDefinitions")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("ReturnDefinition")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<int>("TemplateId")
.HasColumnType("int");
b.Property<string>("TriggerConfiguration")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("TriggerType")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.HasIndex("TemplateId", "Name")
.IsUnique();
b.ToTable("TemplateScripts");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeployedConfigSnapshot", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null)
.WithMany()
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null)
.WithMany()
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemMethod", b =>
{
b.HasOne("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemDefinition", null)
.WithMany()
.HasForeignKey("ExternalSystemDefinitionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Area", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Instances.Area", null)
.WithMany("Children")
.HasForeignKey("ParentAreaId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null)
.WithMany()
.HasForeignKey("SiteId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Instance", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Instances.Area", null)
.WithMany()
.HasForeignKey("AreaId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null)
.WithMany()
.HasForeignKey("SiteId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany()
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceAlarmOverride", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null)
.WithMany("AlarmOverrides")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceAttributeOverride", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null)
.WithMany("AttributeOverrides")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceConnectionBinding", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Sites.DataConnection", null)
.WithMany()
.HasForeignKey("DataConnectionId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null)
.WithMany("ConnectionBindings")
.HasForeignKey("InstanceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationRecipient", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Notifications.NotificationList", null)
.WithMany("Recipients")
.HasForeignKey("NotificationListId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Security.SiteScopeRule", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Security.LdapGroupMapping", null)
.WithMany()
.HasForeignKey("LdapGroupMappingId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null)
.WithMany()
.HasForeignKey("SiteId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.DataConnection", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null)
.WithMany()
.HasForeignKey("SiteId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.Template", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Templates.TemplateFolder", null)
.WithMany()
.HasForeignKey("FolderId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany()
.HasForeignKey("ParentTemplateId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAlarm", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany("Alarms")
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAttribute", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany("Attributes")
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateComposition", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany()
.HasForeignKey("ComposedTemplateId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany("Compositions")
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateFolder", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Templates.TemplateFolder", null)
.WithMany()
.HasForeignKey("ParentFolderId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateScript", b =>
{
b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null)
.WithMany("Scripts")
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Area", b =>
{
b.Navigation("Children");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Instance", b =>
{
b.Navigation("AlarmOverrides");
b.Navigation("AttributeOverrides");
b.Navigation("ConnectionBindings");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationList", b =>
{
b.Navigation("Recipients");
});
modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.Template", b =>
{
b.Navigation("Alarms");
b.Navigation("Attributes");
b.Navigation("Compositions");
b.Navigation("Scripts");
});
#pragma warning restore 612, 618
}
}
}