Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 12 de marzo de 2019
Entity Framework Core Seguimos hablando de características interesantes de Entity Framework Core, y en esta ocasión nos detendremos en las shadow properties, o propiedades ocultas.
A grandes rasgos, se trata de la capacidad de este framework para gestionar propiedades de una entidad que existen en el almacén datos pero no en la clase .NET que la representa en el mundo de los objetos.

De forma intuitiva podemos saber que esto ya existía en las versiones clásicas de Entity Framework. Por ejemplo, cuando introducíamos una propiedad de navegación entre dos entidades sin usar una clave foránea de forma explícita, el propio marco de trabajo creaba, por convención, una columna en la base de datos para almacenar dicha referencia, como en el siguiente escenario:
public class Friend
{
    public int Id { get; set; }
    public string Name { get; set; }
                                            // Se crea una columna CountryId en la base de datos,
    public Country Country { get; set; }    // pero no existe en la entidad.

}
El valor de dicha columna CountryId no podía ser manipulada de forma directa porque se trataba de información usada internamente para gestionar las relaciones y su valor era obtenido y actualizado de forma transparente para nosotros.

Pues bien, Entity Framework Core aporta la capacidad para gestionar este tipo de campos "ocultos" para servir a nuestros propios intereses. De esta forma, podríamos añadir a una entidad propiedades que no tienen por qué estar visibles en la clase .NET en forma de propiedades; un ejemplo podría ser el clásico "IsDeleted" cuando implementamos borrado lógico, o información de auditoría como los tradicionales "UpdatedAt" o "UpdatedBy".

Definición de propiedades ocultas

La definición de shadow properties sólo puede realizarse utilizando el API fluido de configuración disponible a través del objeto ModelBuilder suministrado al método OnModelCreating() del contexto de datos.

Por ejemplo, el siguiente bloque de código añade a la entidad Friend las propiedades ocultas UpdatedAt y UpdatedBy, que podrían sernos de utilidad para almacenar información interna de auditoría:
// Entidad:
public class Friend
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// Contexto de datos:
public class FriendsContext : DbContext
{
    public DbSet<Friend> Friend { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<Friend>()
            .Property<DateTime>("UpdatedAt");
        builder.Entity<Friend>()
            .Property<string>("UpdatedBy").HasMaxLength(80);
    }
}
Y esto es todo, así de sencilla es la creación de shadow properties :)

Consultar o establecer el valor de una propiedad oculta de una entidad

Dado que estas propiedades no aparecen en las clases .NET que representan a las entidades de datos, no podemos acceder a sus valores utilizando expresiones como objeto.Propiedad desde nuestro código. Sus valores están gestionados directamente por el change tracker de Entity Framework, por lo que debemos recurrir a él para hacerlo.

Por ejemplo, el siguiente código muestra cómo acceder a las propiedades ocultas de una entidad obtenida previamente:
var friend = ctx.Friends.FirstOrDefault();
if(friend != null)
{
    var name = friend.Name;
    var updatedBy = ctx.Entry(friend).Property<string>("UpdatedBy").CurrentValue;
    var updatedAt = ctx.Entry(friend).Property<DateTime>("UpdatedAt").CurrentValue;
    Console.WriteLine($"{name} was updated by {updatedBy} at {updatedAt}");
}
De la misma forma, para actualizar el valor de las shadow properties, tendremos que esta la misma shadow property podríamos hacerlo como sigue:
var friend = ctx.Friends.FirstOrDefault();
if(friend != null)
{
    ctx.Entry(friend).Property<string>("UpdatedBy").CurrentValue = "John Smith";
    ctx.Entry(friend).Property<DateTime>("UpdatedAt").CurrentValue = DateTime.Now;
    ctx.SaveChanges();
}

Incluir shadow properties en expresiones de consulta

Obviamente, el hecho de que no tengamos propiedades en la entidad para acceder a estos valores condiciona también la forma en que debemos utilizarlos desde LINQ en los predicados o criterios de consultas.

Pero de nuevo, tenemos una fórmula bastante sencilla para conseguirlo obteniendo una referencia válida para el árbol de expresión a través del método EF.Property(). En el siguiente ejemplo vemos cómo filtrar las entidades para obtener sólo aquellas actualizadas durante el último minuto:
var since = DateTime.Now.AddMinutes(-1);
var friendsRecentlyUpdated = ctx.Friends
    .Where(b => EF.Property<DateTime>(b, "UpdatedAt") > since);
Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!