Темпоральные таблицы в EF Core. Часть 3
1. Что это?
2. Настройка
Запросы
Стандартные операции EF Core (вставка, изменение, удаление) автоматически запускают операции аудита. Чтение текущих значений так же не отличается от обычного.
Расширенные шаблоны запросов
EF Core 7+ предоставляет 5 операторов темпоральных запросов.
1. TemporalAll() — полная история для сущности
var orderHistory = _db.Orders
.TemporalAll()
.Where(o => o.Id == orderId)
.OrderBy(o => EF.Property<DateTime>(o, "ValidFrom"))
.Select(o => new OrderAuditEntry
{
ShippingAddress = o.ShippingAddress,
Status = o.Status,
TotalAmount = o.TotalAmount,
ValidFrom = EF.Property<DateTime>(o, "ValidFrom"),
ValidTo = EF.Property<DateTime>(o, "ValidTo")
})
.ToListAsync();
}
Это покажет нам всю историю заказа (и ответит на претензию клиента – мы будем знать, когда изменился адрес).
2. TemporalAsOf() – снепшот на точку во времени
Воссоздаёт состояние сущности на определённый момент:
var asOf = DateTime.UtcNow.AddDays(-2);
var order = _db.Orders
.TemporalAsOf(asOf)
.Include(o => o.Items)
.FirstOrDefaultAsync(o => o.Id == orderId);
Заметьте: при использовании TemporalAsOf() с Include() EF Core применяет временной фильтр и к связанной сущности. В результате вы получаете OrderItems, существовавшие на тот момент времени, а не текущие позиции.
3. TemporalBetween() — изменения в пределах временного окна
Найти все заказы, которые были изменены в течение определённого временного окна:
var timeWindow = new
{
Start = new DateTime(2026, 6, 11, 3, 0, 0, DateTimeKind.Utc),
End = new DateTime(2026, 6, 11, 4, 0, 0, DateTimeKind.Utc)
};
var changed = await _db.Orders
.TemporalBetween(timeWindow.Start, timeWindow.End)
.Select(o => new
{
o.Id,
o.Status,
ValidFrom = EF.Property<DateTime>(o, "ValidFrom")
})
.ToListAsync();
4. TemporalFromTo() — перекрывающиеся временные диапазоны
Cтроки, которые были активны в течение заданного диапазона, — даже если были созданы раньше:
var ordersActiveLastWeek = await _db.Orders
.TemporalFromTo(
DateTime.UtcNow.AddDays(-7),
DateTime.UtcNow)
.Where(o => o.Status == "Processing")
.ToListAsync();
5. TemporalContainedIn() — строки, полностью находящиеся в заданном диапазоне
Только строки, которые были созданы и удалены в пределах указанного диапазона:
var contained = await _db.Orders
.TemporalContainedIn(
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow)
.ToListAsync();
Продолжение следует…
Источник: https://thecodeman.net/posts/temporal-tables-efcore-auditing-history