Темпоральные таблицы в EF Core. Часть 2
Часть 1
Настройка темпоральных таблиц в EF Core
Системные требования:
- .NET 6+
- EF Core 6+ (Microsoft.EntityFrameworkCore.SqlServer)
- SQL Server 2016+ (или Azure SQL Database)
1. Определяем сущности
// Models/Order.cs
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
// …
public Customer Customer { get; set; } = null!;
public List<OrderItem> Items { get; set; } = [];
}
// Models/OrderItem.cs
public class OrderItem
{
public int Id { get; set; }
public int OrderId { get; set; }
public string Product { get; set; } = "";
public int Quantity { get; set; }
public decimal Price { get; set; }
public Order Order { get; set; } = null!;
}
Обратите внимание, что сами сущности не имеют столбцов аудита — это исключительно вопрос конфигурации уровня данных.
2. Настраиваем DbContext
// Data/AppDbContext.cs
public class AppDbContext : DbContext
{
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderItem> OrderItems => Set<OrderItem>();
public DbSet<Customer> Customers => Set<Customer>();
//…
protected override void
OnModelCreating(ModelBuilder mb)
{
mb.Entity<Order>(e =>
{
e.ToTable("Orders", x => x.IsTemporal(t =>
{
t.HasPeriodStart("ValidFrom");
t.HasPeriodEnd("ValidTo");
t.UseHistoryTable("OrdersHistory", "audit");
}));
e.Property(o => o.TotalAmount)
.HasColumnType("decimal(18,2)");
e.Property(o => o.Status)
.HasMaxLength(50);
});
mb.Entity<OrderItem>(e =>
{
e.ToTable("OrderItems", x => x.IsTemporal(t =>
{
t.HasPeriodStart("ValidFrom");
t.HasPeriodEnd("ValidTo");
t.UseHistoryTable("OrderItemsHistory", "audit");
}));
e.Property(i => i.UnitPrice)
.HasColumnType("decimal(18,2)");
});
}
}
Несколько нюансов:
- схема
audit - таблицы истории размещены в отдельной схеме, что позволяет сохранить основную схему чистой и упрощает управление правами доступа (например, читать audit могут только администраторы);- явное указание имён столбцов периода - ValidFrom/ValidTo — общепринятые имена, но вы можете использовать PeriodStart/PeriodEnd, если хотите;
- и Order и OrderItem, являются временными - нам нужна полная картина.
3. Создаём миграцию
dotnet ef migrations add AddTemporalTables
dotnet ef database update
SQL Server сгенерирует что-то вроде этого:
sql
CREATE TABLE [Orders] (
[Id] INT NOT NULL IDENTITY,
[CustomerId] INT NOT NULL,
…
[ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
[ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo]),
CONSTRAINT [PK_Orders] PRIMARY KEY ([Id])
)
WITH (SYSTEM_VERSIONING = ON (
HISTORY_TABLE = [audit].[OrdersHistory]
));
Продолжение следует…
Источник: https://thecodeman.net/posts/temporal-tables-efcore-auditing-history