Compartir a través de


Atributos de asignación (también conocidos como anotaciones de datos) para relaciones

Los atributos de asignación se usan para modificar o invalidar la configuración detectada por las convenciones de creación de modelos. La configuración realizada por los atributos de asignación se puede invalidar mediante la API de compilación de modelos utilizada en OnModelCreating.

Importante

En este documento, solo se tratan los atributos de asignación en el contexto de la configuración de relaciones. Se tratan otros usos de los atributos de asignación en las secciones pertinentes de la documentación sobre modelado más amplia.

Sugerencia

El código siguiente se puede encontrar en el archivo MappingAttributes.cs.

Dónde obtener atributos de asignación

Muchos atributos de asignación proceden de los espacios de nombres System.ComponentModel.DataAnnotations y System.ComponentModel.DataAnnotations.Schema. Los atributos de estos espacios de nombres se incluyen como parte del marco base en todas las versiones compatibles de .NET, por lo que no requieren la instalación de ningún paquete NuGet adicional. Estos atributos de asignación se llaman normalmente "anotaciones de datos" y se usan en una variedad de marcos, como EF Core, EF6, ASP.NET Core MVC, etc. También se usan para la validación.

El uso de anotaciones de datos en muchas tecnologías, y tanto para la asignación como para la validación, ha provocado diferencias en la semántica de las distintas tecnologías. Todos los nuevos atributos de asignación diseñados para EF Core ahora son específicos de EF Core, con lo que se mantiene su semántica y se usa de forma sencilla y clara. Estos atributos se encuentran en el paquete NuGet Microsoft.EntityFrameworkCore.Abstractions. Este paquete se incluye como una dependencia cada vez que se usa el paquete principal Microsoft.EntityFrameworkCore o uno de los paquetes de proveedor de base de datos asociados. Sin embargo, el paquete Abstractions es un paquete ligero al que el código de la aplicación puede hacer referencia directamente sin incluir todo EF Core y sus dependencias.

RequiredAttribute

El elemento RequiredAttribute se aplica a una propiedad para indicar que la propiedad no puede ser null. En el contexto de las relaciones, normalmente se usa [Required] en una propiedad de clave externa. En este caso, la clave externa no admite valores NULL, lo que hace que la relación sea obligatoria. Por ejemplo, con los siguientes tipos, la propiedad Post.BlogId no acepta valores NULL y la relación se convierte en obligatoria.

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [Required]
    public string BlogId { get; set; }

    public Blog Blog { get; init; }
}

Nota

Cuando se usan tipos de referencia que aceptan valores NULL de C#, la propiedad BlogId de este ejemplo ya no admite valores NULL, lo que significa que el atributo [Required] no tendrá ningún efecto.

Cuando se coloca [Required] en la navegación dependiente, tiene el mismo efecto. Es decir, hace que la clave externa no acepte valores NULL y, por tanto, haga obligatoria la relación. Por ejemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    public string BlogId { get; set; }

    [Required]
    public Blog Blog { get; init; }
}

Si [Required] está en la navegación dependiente y la propiedad de clave externa está en estado reemplazado, la propiedad reemplazada se convierte en una que no acepta valores NULL, lo que hace obligatoria la relación. Por ejemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [Required]
    public Blog Blog { get; init; }
}

Nota

El uso de [Required] en el lado de la navegación principal de una relación no tiene ningún efecto.

ForeignKeyAttribute

ForeignKeyAttribute se usa para conectar una propiedad de clave externa con sus navegaciones. [ForeignKey] se puede colocar en la propiedad de clave externa con el nombre de la navegación dependiente. Por ejemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [ForeignKey(nameof(Blog))]
    public string BlogKey { get; set; }

    public Blog Blog { get; init; }
}

O bien, se puede colocar [ForeignKey] en la navegación dependiente o principal con el nombre de la propiedad que se va a usar como clave externa. Por ejemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    public string BlogKey { get; set; }

    [ForeignKey(nameof(BlogKey))]
    public Blog Blog { get; init; }
}

Cuando se coloca [ForeignKey] en una navegación y el nombre proporcionado no coincide con ningún nombre de propiedad, se creará una propiedad reemplazada con ese nombre para que actúe como clave externa. Por ejemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [ForeignKey("BlogKey")]
    public Blog Blog { get; init; }
}

InversePropertyAttribute

InversePropertyAttribute se usa para conectar una navegación con su inversa. Por ejemplo, en los siguientes tipos de entidad, hay dos relaciones entre Blog y Post. Sin ninguna configuración, las convenciones de EF no pueden determinar qué navegaciones entre los dos tipos se deben emparejar. Agregar [InverseProperty] a una de las navegaciones emparejadas resuelve esta ambigüedad y permite a EF crear el modelo.

public class Blog
{
    public int Id { get; set; }

    [InverseProperty("Blog")]
    public List<Post> Posts { get; } = new();

    public int FeaturedPostId { get; set; }
    public Post FeaturedPost { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; }

    public Blog Blog { get; init; }
}

Importante

[InverseProperty] solo es necesario cuando hay más de una relación entre los mismos tipos. Con una sola relación, las dos navegaciones se emparejan automáticamente.

DeleteBehaviorAttribute

Por convención, EF usa ClientSetNull DeleteBehavior para las relaciones opcionales y el comportamiento Cascade para las relaciones obligatorias. Esto se puede cambiar colocando DeleteBehaviorAttribute en una de las navegaciones de la relación. Por ejemplo:

public class Blog
{
    public int Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; }

    [DeleteBehavior(DeleteBehavior.Restrict)]
    public Blog Blog { get; init; }
}

Consulte Eliminación en cascada para obtener más información sobre los comportamientos en cascada.