Interceptors в EntityFramework Core или EF Core Перехватчики

Полезности | создано: 17.08.2024 | опубликовано: 15.03.2025 | обновлено: 17.03.2025 | просмотров: 82

Перехватчики Entity Framework Core (EF Core) позволяют перехватывать, изменять и (или) подавлять операции EF Core. Сюда входят низкоуровневые операции с базой данных, такие как выполнение команды, а также операции более высокого уровня, такие как вызовы SaveChanges.

Описание

Entity Framework Core (EF Core) — это мощное и гибкое объектно-реляционное сопоставление (ORM) для разработчиков .NET. Помимо своих функций, перехватчики предоставляют механизм подключения к конвейеру EF Core, позволяя разработчикам проверять, изменять или дополнять операции EF Core. В этом руководстве объясняются перехватчики, как они работают и их практическое применение с примерами.

Типы перехватчиков Interceptors

EF Core предоставляет несколько встроенных интерфейсов для определения перехватчиков:

  1. IDbCommandInterceptor: Для выполнения команд базы данных.
  2. ISaveChangesInterceptor: Для перехвата операций SaveChanges.
  3. IQueryExpressionInterceptor: для перехвата выражений запроса LINQ.
  4. IConnectionInterceptor: для операций подключения к базе данных.
  5. ITransactionInterceptor: Для перехвата операций, связанных с транзакциями.

Примеры

Это один из возможных примеров использования Interceptor при реализации SoftDelete. То есть, когда сущность не удаляется реально из БД, а помечается специальным образом, чтобы при выборке обычных сущностей удаленные был исключены.

public class SoftDeleteInterceptor : ISaveChangesInterceptor
{
    public override int SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
    {
        var context = eventData.Context;
        if (context == null) return base.SavingChanges(eventData, result);

        foreach (var entry in context.ChangeTracker.Entries())
        {
            // Handle entities with IsDeleted property
            if (entry.Entity is ISoftDeletable softDeletableEntity && entry.State == EntityState.Deleted)
            {
                entry.State = EntityState.Modified;
                softDeletableEntity.IsDeleted = true;

                // Update related entities if required for complex relationships
                if (entry.Entity is ITenantEntity tenantEntity)
                {
                    HandleTenantSpecificLogic(context, tenantEntity);
                }
            }
        }

        return base.SavingChanges(eventData, result);
    }

    private void HandleTenantSpecificLogic(DbContext context, ITenantEntity tenantEntity)
    {
        // Example: Ensure related tenant-specific records are soft-deleted or flagged appropriately
        var relatedEntities = context.ChangeTracker.Entries()
            .Where(e => e.Entity is IRelatedEntity && ((IRelatedEntity)e.Entity).TenantId == tenantEntity.TenantId);

        foreach (var relatedEntity in relatedEntities)
        {
            if (relatedEntity.State == EntityState.Deleted)
            {
                relatedEntity.State = EntityState.Modified;
                ((IRelatedEntity)relatedEntity.Entity).IsDeleted = true;
            }
        }
    }
}

Видео

Ссылки