Intercettare gli eventi di creazione degli oggetti con Entity Framework 7

di Stefano Mostarda, in LINQ, Entity Framework,

Versione dopo versione, il team di EF ha aggiunto diversi punti di estensione per intercettare eventi nel momento in cui questi si verificano. I primi punti di intercettazione sono stati quelli che si inserivano nella pipeline di esecuzione del codice SQL. Successivamente si sono aggiunti eventi per la fase di aggiunta e rimozione delle entity dal meccanismo di tracking e per la fase precedente e successiva alla persistenza sul database.

Entity Framework 7 introduce nuovi punti di estensione tra cui quello relativo alla materializzazione delle entity. La materializzazione è il processo di creazione dell'entity e il successivo popolamento delle proprietà partendo dai dati provenienti dalle query fatte al database. Se vogliamo personalizzare il processo di materializzazione, dobbiamo creare un interceptor che implementa l'interfaccia IMaterializationInterceptor e implementare almeno uno dei metodi dell'interfaccia (che fornisce già un'implementazione di base).

  • CreatingInstance: invocato prima di istanziare l'entity. Implementando questo metodo possiamo creare noi l'entity scartando l'istanza creata da EF. Torna utile quando vogliamo usare una factory per creare le entity;
  • CreatedInstance: invocato dopo che l'entity è stata istanziata;
  • InitializingInstance: invocato prima di popolare le proprietà dell'entity;
  • InitializedInstance: invocato dopo aver popolato le proprietà dell'entity;

Supponiamo di dover mantenere nelle entity la data di materializzazione dal database, in questo caso possiamo far implementare un'interfaccia alle entity e nel metodo InitializedInstanze verificare che se l'entity materializzata implementa quell'interfaccia allora andiamo a popolare la data di materializzazione.

public interface IHasMaterializationDate
{
    DateTime MaterializationDate { get; set; }
}

public class Person : IHasMaterializationDate
{
    public int Id { get; set; }
    public string Name { get; set; } = null!;

    [NotMapped]
    public DateTime MaterializationDate { get; set; }
}

public class MaterializationDateInterceptor : IMaterializationInterceptor
{
    public object InitializedInstance(MaterializationInterceptionData materializationData, object instance)
    {
        if (instance is IHasMaterializationDate hasMaterializationDate)
        {
            hasMaterializationDate.MaterializationDate = DateTime.UtcNow;
        }

        return instance;
    }
}

Una volta creato l'interceptor, non ci resta che aggiungerlo alla lista degli interceptor in fase di configurazione utilizzando le API di EF già esistenti.

public class PeopleContext : DbContext
{
  private static readonly MaterializationDateInterceptor _materializationDateInterceptor = new();

  public DbSet<Person> People => Set<Person>();

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => 
    optionsBuilder
      .AddInterceptors(_materializationDateInterceptor)
      .UseSqlServer(connectionstring);
} 

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi