feat(kpi): K2 — KpiSample EF mapping + KpiHistoryRepository + AddKpiSampleTable migration

This commit is contained in:
Joseph Doherty
2026-06-17 19:44:51 -04:00
parent 460777bffa
commit cabc557629
8 changed files with 2151 additions and 0 deletions
@@ -0,0 +1,55 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Configurations;
/// <summary>
/// Maps the <see cref="KpiSample"/> POCO to the central <c>KpiSample</c> table
/// (M6 "KPI History &amp; Trends") — the tall / EAV row written by the recorder
/// singleton. Operational history, NOT audit, so the table is non-partitioned,
/// standard <c>[PRIMARY]</c> filegroup, no DB-role restriction.
/// </summary>
/// <remarks>
/// Two named indexes back the access paths: <c>IX_KpiSample_Series</c> covers the
/// bucketed series query (filter by Source/Metric/Scope/ScopeKey, ordered by
/// capture time) and <c>IX_KpiSample_Captured</c> backs the retention purge
/// (delete by <see cref="KpiSample.CapturedAtUtc"/>).
/// </remarks>
public class KpiSampleEntityTypeConfiguration : IEntityTypeConfiguration<KpiSample>
{
/// <summary>
/// Configures the EF Core entity type mapping for <see cref="KpiSample"/>.
/// </summary>
/// <param name="builder">The entity type builder to configure.</param>
public void Configure(EntityTypeBuilder<KpiSample> builder)
{
builder.ToTable("KpiSample");
// Surrogate long identity assigned by the store.
builder.HasKey(s => s.Id);
// Catalog-bounded ASCII columns — values come from the KpiSources /
// KpiScopes catalogs and per-source metric names.
builder.Property(s => s.Source).HasMaxLength(64).IsUnicode(false).IsRequired();
builder.Property(s => s.Metric).HasMaxLength(64).IsUnicode(false).IsRequired();
builder.Property(s => s.Scope).HasMaxLength(16).IsUnicode(false).IsRequired();
// Scope qualifier — null for the Global scope.
builder.Property(s => s.ScopeKey).HasMaxLength(64).IsUnicode(false);
// Measured value — double / float column.
builder.Property(s => s.Value);
builder.Property(s => s.CapturedAtUtc).IsRequired();
// Series index — backs the bucketed query path (filter one series, scan in
// capture order). Names locked for migration discoverability.
builder.HasIndex(s => new { s.Source, s.Metric, s.Scope, s.ScopeKey, s.CapturedAtUtc })
.HasDatabaseName("IX_KpiSample_Series");
// Captured index — backs the retention purge (delete by capture time).
builder.HasIndex(s => s.CapturedAtUtc)
.HasDatabaseName("IX_KpiSample_Captured");
}
}