TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.74K subscribers
Post #3218 1.78K
День 2688. #ЗаметкиНаПолях
Темпоральные таблицы в 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
  • 👍 7
  • 👎 1
More from @netdeveloperdiary
  1. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  2. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  3. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  4. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  5. Sep 22, 2026День 2792. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  6. Sep 21, 2026🔍Тестовое собеседование с Senior C# разработчиком уже завтра 22 сентября(уже завтра!) в 1…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →