using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using ScadaLink.Commons.Entities.Deployment; using ScadaLink.ConfigurationDatabase; namespace ScadaLink.ConfigurationDatabase.Tests; /// /// Test DbContext that adapts SQL Server-specific features for SQLite: /// - Maps DateTimeOffset to sortable ISO 8601 strings (SQLite has no native DateTimeOffset ORDER BY) /// - Replaces SQL Server RowVersion with a nullable byte[] column (SQLite can't auto-generate rowversion) /// public class SqliteTestDbContext : ScadaLinkDbContext { public SqliteTestDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // SQLite cannot auto-generate SQL Server rowversion values. // Replace with a nullable byte[] column so inserts don't fail with NOT NULL constraint. modelBuilder.Entity(builder => { builder.Property(d => d.RowVersion) .IsRequired(false) .IsConcurrencyToken(false) .ValueGeneratedNever(); }); // Convert DateTimeOffset to ISO 8601 string for SQLite so ORDER BY works var converter = new ValueConverter( v => v.UtcDateTime.ToString("o"), v => DateTimeOffset.Parse(v)); var nullableConverter = new ValueConverter( v => v.HasValue ? v.Value.UtcDateTime.ToString("o") : null, v => v != null ? DateTimeOffset.Parse(v) : null); foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { foreach (var property in entityType.GetProperties()) { if (property.ClrType == typeof(DateTimeOffset)) { property.SetValueConverter(converter); property.SetColumnType("TEXT"); } else if (property.ClrType == typeof(DateTimeOffset?)) { property.SetValueConverter(nullableConverter); property.SetColumnType("TEXT"); } } } } } public static class SqliteTestHelper { public static ScadaLinkDbContext CreateInMemoryContext() { var options = new DbContextOptionsBuilder() .UseSqlite("DataSource=:memory:") .ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)) .Options; var context = new SqliteTestDbContext(options); context.Database.OpenConnection(); context.Database.EnsureCreated(); return context; } public static ScadaLinkDbContext CreateFileContext(string dbPath) { var options = new DbContextOptionsBuilder() .UseSqlite($"DataSource={dbPath}") .ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)) .Options; var context = new SqliteTestDbContext(options); return context; } }