Soft Deleted con Entity Framework 6 y Dynamics Filter

Veremos como filtrar automáticamente todas las consultas a nuestra DB ignorando los registros eliminados usando Entity Framework 6.

Rodríguez Patiño, Eduardo
2020-09-27 | 5,811 lecturas

En esta entrada vamos aplicar la técnica de Soft Deleted automáticamente, es decir que vamos a ignorar los registrados que hayamos eliminado a nivel lógico (quiere decir que actualizamos un campo para determinar si fué eliminado en vez de ejecutar un DELETE FROM ..).

Agregando EntityFramework.DynamicFilters a nuestro proyecto

Este package (EntityFramework.DynamicFilters) del NuGet nos permite crear filtros personalizados a nuestro DbContext, en este caso yo voy agregar el filtro para que ignore de las consultas los registros que han sido eliminado. Bien, agreguen del Nugget el siguiente package que lo encuentran escribiendo EntityFramework.DynamicFilters.

Creando la interface ISoftDeleted

Vamos a crear una interfaz para que nuestro filtro sepa a que clases tomar en cuenta.

public interface ISoftDeleted
{
    bool IsDeleted { get; set; }
}

Agregando nuestros filtros al DbContext

Ahora vamos a crear un nuevo método en nuestro contexto que recibirá como parámetro nuestro DbModelBuilder, en este vamos a configurar nuestros filtros. En el ejemplo a continuación le estoy diciendo que cree un filtro para las clases que implementan la interfaz ISoftDeleted y que por detecto la columna debe ser == false.

private void AddMyFilters(ref DbModelBuilder modelBuilder)
{
    modelBuilder.Filter("IsDeleted", (ISoftDeleted d) => d.IsDeleted, false);
}

Y luego lo invocamos

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // ...
    AddMyFilters(ref modelBuilder);
}

Con esto ya todas nuestras consultas tendrán el filtro por defecto, no se olviden correr la migración para aplicar los cambios a las clases que han implementado la interfaz ISoftDeleted.

Ejemplo en acción

La consulta a continuación va a reconocer el filtro y lo sumará a nuestro Where para que ignore el filtro.

public static IEnumerable<Empleado> GetAll()
{
    var result = new List<Empleado>();

    using (var ctx = new DatabaseContext()) {
        result = ctx.Empleado.Include(x => x.Profesion).ToList();
    }

    return result;
}

En caso de no aplicar filtros tendríamos que hacer lo siguiente.

public static IEnumerable<Empleado> GetAll()
{
    var result = new List<Empleado>();

    using (var ctx = new DatabaseContext())
    {
        ctx.DisableFilter("IsDeleted");
        result = ctx.Empleado.Include(x => x.Profesion).Where(x => !x.IsDeleted).ToList();
        ctx.EnableFilter("IsDeleted");
    }

    return result;
}

Y el trabajo sería más pesado porque tendriamos que repetir el Where en todas las consultas. Adicionalmente, también tendríamos que incluir la condición a las relaciones de una clase. En este caso, con el filtro cubre cualquier consulta que se haga que implemente la interfaz ISoftDeleted.

Tips

El Dynamics Filter se me ocurrió para implementar el Soft Deleted pero podemos hacer muchas cosas. Por ejemplo, tenemos un sistema que es multiempresa, es decir cada usuario tiene asignado una empresa, podríamos crear un filtro para que todo los querys tengan por defecto la empresa que tiene asignado el usuario.