TGViewer
C# 1001 notes C# 1001 notes @csharp_1001_notes · 6.65K subscribers
Post #401 3.83K
🖥 Перехватчики в EF Core

Перехватчики в EF Core помогают перехватывать, изменять или подавлять операции EF Core.

Перехватчики регистрируются для каждого экземпляра DbContext при настройке контекста. Каждый перехватчик реализует интерфейс IInterceptor. Несколько распространённых производных интерфейсов включают

- IDbCommandInterceptor,
- IDbConnectionInterceptor,
- IDbTransactionInterceptor,
- ISaveChangesInterceptor.

Вам не нкжно реализовывать эти интерфейсы напрямую.

Лучше использовать конкретные реализации и переопределить необходимые методы.
Вот вариант использования перехватчиков с помощью самого распространённого перехватчика SaveChangesInterceptor, который добавляет поведение при сохранении изменений в базе данных.

Добавление записей аудита
Записи аудита изменений сущностей - ценная функция в некоторых приложениях. Вы записываете дополнительную информацию аудита каждый раз, когда объект создаётся или изменяется. Также это могут быть значения «до» и «после», в зависимости от ваших требований.
Например, создадим интерфейс IAuditable с датами создания и изменения объекта:
public interface IAuditable
{
DateTime Created { get; }
DateTime? Modified { get; }
}

Добавим UpdateInterceptor для записи значений аудита. Он использует ChangeTracker для поиска всех экземпляров IAuditable и устанавливает соответствующее значение свойства. Здесь мы используем метод SavingChangesAsync, который запускается до того, как изменения будут сохранены в БД.
internal sealed class UpdateInterceptor
: SaveChangesInterceptor
{
public override
ValueTask<InterceptionResult<int>>
SavingChangesAsync(
DbContextEventData e,
InterceptionResult<int> result,
CancellationToken ct = default)
{
if (e.Context is not null)
UpdateEntities(e.Context);

return base
.SavingChangesAsync(e, result, ct);
}

private static void
UpdateEntities(DbContext ctx)
{
var now = DateTime.UtcNow;
var entities = ctx
.ChangeTracker
.Entries<IAuditable>()
.ToList();

foreach (var e in entities)
{
if (e.State == EntityState.Added)
e.Property(
nameof(IAuditable.Created)) = now;

if (e.State == EntityState.Modified)
e.Property(
nameof(IAuditable.Modified)) = now;
}
}
}

Эту реализацию можно легко расширить, включив в неё, например, информацию о текущем пользователе.

Зарегистрировать перехватчик можно следующим образом:

services.AddSingleton<UpdateInterceptor>();
services.AddDbContext<
IApplicationDbContext,
AppDbContext>(
(sp, opts) => opts
.UseSqlServer(connString)
.AddInterceptors(
sp.GetRequiredService<UpdateInterceptor>());


👉 Подробнее

@csharp_1001_notes
More from @csharp_1001_notes
  1. Sep 24, 2026Ваш .NET API работает локально. Готов ли он к продакшену? Чек-лист из 8 проверок перед рел…
  2. Sep 20, 2026🧩 C# Channels: сообщение попало в очередь. Почему обработчик его не получил? Два воркера…
  3. Sep 16, 2026Эта задача проверяет понимание Memory<T>, pooling, ownership, IAsyncEnumerable, cancellati…
  4. Sep 16, 2026# C# 14: хитрая задача на ArrayPool, IAsyncEnumerable и время жизни памяти Есть поток данн…
  5. Sep 14, 2026# C# 14: конкурентный кеш без race condition Реализуйте потокобезопасный кеш: public seale…
  6. Sep 14, 2026🔍Тестовое собеседование с Senior C# разработчиком уже завтра 15 сентября(уже завтра!) в 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 →