Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las relaciones uno a uno se usan cuando una entidad está asociada con, como máximo, otra entidad. Por ejemplo, un Blog
tiene un BlogHeader
y que BlogHeader
pertenece a un único Blog
.
Este documento se estructura en torno a una gran cantidad de ejemplos. Los ejemplos comienzan con casos comunes, que también presentan conceptos. En los ejemplos posteriores se tratan tipos menos comunes de configuración. Un buen enfoque aquí es comprender los primeros ejemplos y conceptos y, a continuación, ir a los ejemplos posteriores en función de sus necesidades específicas. En función de este enfoque, comenzaremos con relaciones simples "obligatorias" y "opcionales" uno a uno.
Sugerencia
El código de todos los ejemplos siguientes se puede encontrar en OneToOne.cs.
Se requiere correspondencia individual
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
Una relación uno a uno se compone de:
- Una o varias propiedades de clave principal o alternativa en la entidad principal. Por ejemplo:
Blog.Id
. - Una o varias propiedades de clave externa en la entidad dependiente. Por ejemplo:
BlogHeader.BlogId
. - Opcionalmente, una navegación de referencia en la entidad principal que hace referencia a la entidad dependiente. Por ejemplo:
Blog.Header
. - Opcionalmente, una navegación de referencia en la entidad dependiente que hace referencia a la entidad principal. Por ejemplo:
BlogHeader.Blog
.
Sugerencia
No siempre es obvio qué lado de una relación uno a uno debe ser el principal y qué lado debe ser el dependiente. Algunas consideraciones son:
- Si las tablas de base de datos de los dos tipos ya existen, la tabla con las columnas de clave externa debe asignarse al tipo dependiente.
- Un tipo suele ser el tipo dependiente si no puede existir lógicamente sin el otro tipo. Por ejemplo, no tiene sentido tener un encabezado para un blog que no existe, por lo que
BlogHeader
es naturalmente el tipo dependiente. - Si hay una relación natural de padre/madre e hijo/a, entonces el hijo suele ser del tipo dependiente.
Por lo tanto, para la relación de este ejemplo:
- La propiedad de clave externa
BlogHeader.BlogId
no es anulable. Esto hace que la relación sea "obligatoria" porque cada dependiente (BlogHeader
) debe estar relacionado con algún principal (Blog
), ya que su propiedad de clave externa debe establecerse en algún valor. - Ambas entidades tienen navegaciones que apuntan a la entidad relacionada en el otro lado de la relación.
Nota:
Una relación necesaria garantiza que todas las entidades dependientes deben estar asociadas a alguna entidad principal. Sin embargo, una entidad principal siempre puede existir sin ninguna entidad dependiente. Es decir, una relación necesaria no indica que siempre habrá una entidad dependiente. No hay manera en el modelo de EF, ni tampoco una forma estándar en una base de datos relacional, de garantizar que una entidad principal esté asociada a un dependiente. Si esto es necesario, debe implementarse en la lógica de la aplicación (negocios). Consulte Navegación necesaria para obtener más información.
Sugerencia
Una relación con dos navegaciones: una de dependiente a principal y una inversa de principal a dependiente, se conoce como una relación bidireccional.
Esta relación se detecta por convención. Es decir:
-
Blog
se descubre como la entidad principal en la relación, yBlogHeader
se descubre como dependiente. -
BlogHeader.BlogId
se ha identificado como una clave externa de la entidad dependiente que hace referencia a la clave principal de la entidad principalBlog.Id
. La relación se detecta según sea necesario porqueBlogHeader.BlogId
no admite valores NULL. -
Blog.BlogHeader
se detecta como una navegación de referencia. -
BlogHeader.Blog
se detecta como una navegación de referencia.
Importante
Cuando se usan tipos de referencia nullable de C#, la navegación desde el dependiente hasta la entidad principal debe ser nullable si la propiedad de clave externa es nullable. Si la propiedad de clave externa no admite valores nulos, la navegación puede ser nula o no. En este caso, BlogHeader.BlogId
no admite valores NULL y BlogHeader.Blog
también no acepta valores NULL. La = null!;
construcción se usa para marcar esto como intencionada para el compilador de C#, ya que EF normalmente establece la Blog
instancia y no puede ser null para una relación totalmente cargada. Consulte Trabajar con tipos de referencia que aceptan valores NULL para obtener más información.
En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
En el ejemplo anterior, la configuración de las relaciones inicia el tipo de entidad principal (Blog
). Al igual que con todas las relaciones, es exactamente equivalente a empezar con el tipo de entidad dependiente (BlogHeader
) en su lugar. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne(e => e.Header)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Ninguna de estas opciones es mejor que la otra; ambos dan como resultado exactamente la misma configuración.
Sugerencia
Nunca es necesario configurar una relación dos veces, una vez empezando desde el principal, y luego otra vez desde el dependiente. Además, intentar configurar la parte principal y la parte dependiente de una relación por separado generalmente no funciona. Elija configurar cada relación desde un extremo u otro y, a continuación, escriba el código de configuración solo una vez.
Opcional uno a uno
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int? BlogId { get; set; } // Optional foreign key property
public Blog? Blog { get; set; } // Optional reference navigation to principal
}
Esto es lo mismo que el ejemplo anterior, excepto que la propiedad de clave externa y la navegación a la entidad principal ahora admiten valores nulos. Esto hace que la relación sea "opcional" porque un dependiente (BlogHeader
) no puede estar relacionado con ningún principal (Blog
) al establecer su propiedad de clave externa y navegación en null
.
Importante
Cuando se utilizan nullable reference types de C#, la propiedad de navegación del dependiente al principal debe ser nullable si la propiedad de clave externa es nullable. En este caso, BlogHeader.BlogId
es nullable, por lo que BlogHeader.Blog
también debe ser nullable. Consulte Trabajar con tipos de referencia que aceptan valores NULL para obtener más información.
Como antes, esta relación se detecta por convención. En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired(false);
}
Se requiere una relación uno a uno entre claves primarias
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
A diferencia de las relaciones uno a varios, el extremo dependiente de una relación uno a uno puede utilizar su propiedad o propiedades de clave principal como propiedad o propiedades de clave externa. A menudo se denomina relación PK-to-PK. Esto solo es posible cuando los tipos principales y los tipos dependientes tienen los mismos tipos de clave principal y la relación resultante siempre es necesaria, ya que la clave principal del dependiente no puede ser nula.
Cualquier relación uno a uno en la que la clave externa no se detecta por convención debe configurarse para indicar las partes principal y dependiente de la relación. Normalmente, esto se realiza con una llamada a HasForeignKey
. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>();
}
Sugerencia
HasPrincipalKey
también se puede usar para este propósito, pero hacerlo es menos común.
Cuando no se especifica ninguna propiedad en la llamada a HasForeignKey
y la clave principal es adecuada, se usa como clave externa. En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.Id)
.IsRequired();
}
Se requiere uno a uno con la clave externa de sombra
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
En algunos casos, es posible que no desee una propiedad de clave externa en el modelo, ya que las claves externas son un detalle de cómo se representa la relación en la base de datos, que no es necesaria cuando se usa la relación de forma puramente orientada a objetos. Sin embargo, si las entidades se van a serializar, por ejemplo, para enviar por un cable, los valores de clave externa pueden ser una manera útil de mantener intacta la información de la relación cuando las entidades no están en forma de objeto. Por lo tanto, a menudo es pragmático mantener las propiedades de clave externa en el tipo .NET para este propósito. Las propiedades de clave externa pueden ser privadas, lo que suele ser un buen compromiso para evitar exponer la clave externa y al mismo tiempo permitir que su valor viaje con la entidad.
A continuación del ejemplo anterior, este ejemplo quita la propiedad de clave externa del tipo de entidad dependiente. Sin embargo, en lugar de usar la clave principal, a EF se le indica que cree una propiedad de clave externa sombreada denominada BlogId
de tipo int
.
Un punto importante que hay que tener en cuenta aquí es que se utilizan tipos de referencia nulos de C#, por lo que la nulabilidad de la navegación de dependiente a principal se usa para determinar si las propiedades de clave externa son nulas y, por lo tanto, si la relación es opcional o necesaria. Si no se usan tipos de referencia que aceptan valores NULL, la propiedad shadow foreign key será nullable de forma predeterminada, lo que hace que la relación sea opcional de forma predeterminada. En este caso, use IsRequired
para forzar que la propiedad de clave externa sombreada no sea nullable y haga que la relación sea obligatoria.
Esta relación nuevamente necesita configuración para indicar los extremos principal y dependiente.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId");
}
En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
Opcional de uno a uno con la clave externa de sombra
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog? Blog { get; set; } // Optional reference navigation to principal
}
Al igual que en el ejemplo anterior, la propiedad de clave foránea se ha quitado del tipo de entidad dependiente. Sin embargo, a diferencia del ejemplo anterior, esta vez se crea la propiedad de clave externa como que acepta valores NULL porque se usan tipos de referencia que aceptan valores NULL de C# y la navegación en el tipo de entidad dependiente admite valores NULL. Esto hace que la relación sea opcional.
Cuando los tipos de referencia que aceptan valores NULL de C# no se usan, la propiedad de clave externa se creará de forma predeterminada como que acepta valores NULL. Esto significa que las relaciones con las propiedades de sombra creadas automáticamente son opcionales de forma predeterminada.
Al igual que antes, esta relación necesita cierta configuración para indicar las partes principales y dependientes.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId");
}
En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired(false);
}
Uno a uno sin navegación a la principal
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
}
En este ejemplo, se ha vuelto a introducir la propiedad de clave externa, pero se ha eliminado la navegación en la entidad dependiente.
Sugerencia
Una relación con solo una navegación, ya sea de dependiente a principal o de principal a dependiente, pero no ambas, se conoce como una relación unidireccional.
Esta relación se detecta por convención, ya que se detecta la clave externa, lo que indica el lado dependiente. En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Observe que la llamada a WithOne
no tiene argumentos. Esta es la manera de indicar a EF que no hay navegación desde BlogHeader
a Blog
.
Si la configuración comienza desde la entidad sin navegación, el tipo de la entidad en el otro extremo de la relación debe especificarse explícitamente mediante la llamada genérica HasOne<>()
. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne<Blog>()
.WithOne(e => e.Header)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Uno a uno sin navegación hacia el principal y con una clave externa oculta
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
}
En este ejemplo, se combinan dos de los ejemplos anteriores eliminando la propiedad de clave externa y la navegación en el dependiente.
Al igual que antes, esta relación necesita cierta configuración para indicar las partes principales y dependientes.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
Se puede usar una configuración más completa para configurar explícitamente el nombre de la clave externa y la navegación, con una llamada adecuada a IsRequired()
o IsRequired(false)
según sea necesario. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
Uno a uno sin navegación hacia el dependiente
// Principal (parent)
public class Blog
{
public int Id { get; set; }
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
Los dos ejemplos anteriores tenían navegaciones desde el principal hacia los dependientes, pero ninguna navegación desde el dependiente hacia el principal. Para el siguiente par de ejemplos, se vuelve a introducir la navegación en el dependiente, mientras que se quita la navegación en el principal.
Por convención, EF tratará esto como una relación uno a varios. Se necesita una configuración mínima para que sea uno a uno:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne();
}
Observe de nuevo que WithOne()
se llama sin argumentos para indicar que no hay ninguna navegación en esta dirección.
En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Si la configuración comienza desde la entidad sin navegación, el tipo de la entidad en el otro extremo de la relación debe especificarse explícitamente mediante la llamada genérica HasOne<>()
. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Uno a uno sin navegación
En ocasiones, puede ser útil configurar una relación sin navegación. Esta relación solo se puede manipular cambiando el valor de clave externa directamente.
// Principal (parent)
public class Blog
{
public int Id { get; set; }
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
}
Esta relación no se detecta por convención, ya que no hay ninguna navegación que indique que los dos tipos están relacionados. Se puede configurar explícitamente en OnModelCreating
. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne();
}
Con esta configuración, la BlogHeader.BlogId
propiedad todavía se detecta como la clave externa por convención y la relación es "necesaria" porque la propiedad de clave externa no admite valores NULL. La relación se puede convertir en "opcional" haciendo que la propiedad de clave externa acepte valores NULL.
Una configuración explícita más completa de esta relación es::
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Uno a uno con clave alternativa
En todos los ejemplos hasta ahora, la propiedad de clave externa del dependiente está restringida a la propiedad de clave principal en el principal. En su lugar, la clave externa se puede restringir a una propiedad diferente, que luego se convierte en una clave alternativa para el tipo de entidad principal. Por ejemplo:
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public int AlternateId { get; set; } // Alternate key as target of the BlogHeader.BlogId foreign key
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
Esta relación no se detecta por convención, ya que EF siempre, por convención, creará una relación con la clave principal. Se puede configurar explícitamente en OnModelCreating
mediante una llamada a HasPrincipalKey
. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => e.AlternateId);
}
HasPrincipalKey
se puede combinar con otras llamadas para configurar explícitamente las navegaciones, las propiedades de clave externa y la naturaleza obligatoria o opcional. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => e.AlternateId)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
Uno a uno con clave externa compuesta
En todos los ejemplos hasta ahora, la propiedad de clave principal o alternativa del principal consistía en una sola propiedad. Las claves principales o alternativas también se pueden formar con más de una propiedad; estas se conocen como "claves compuestas". Cuando el principal de una relación tiene una clave compuesta, la clave foránea de la dependiente también debe ser una clave compuesta con el mismo número de propiedades. Por ejemplo:
// Principal (parent)
public class Blog
{
public int Id1 { get; set; } // Composite key part 1
public int Id2 { get; set; } // Composite key part 2
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId1 { get; set; } // Required foreign key property part 1
public int BlogId2 { get; set; } // Required foreign key property part 2
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
Esta relación se descubre por convención. Sin embargo, solo se detectará si la clave compuesta se ha configurado explícitamente, ya que las claves compuestas no se detectan automáticamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasKey(e => new { e.Id1, e.Id2 });
}
Importante
Se considera que un valor de clave externa compuesta es null
si alguno de sus valores de propiedad es NULL. Una clave externa compuesta con una propiedad NULL y otra que no sea NULL no se considerará una coincidencia para una clave principal o alternativa con los mismos valores. Ambos se considerarán null
.
Tanto HasForeignKey
como HasPrincipalKey
se pueden usar para especificar explícitamente claves con varias propiedades. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(
nestedBuilder =>
{
nestedBuilder.HasKey(e => new { e.Id1, e.Id2 });
nestedBuilder.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => new { e.Id1, e.Id2 })
.HasForeignKey<BlogHeader>(e => new { e.BlogId1, e.BlogId2 })
.IsRequired();
});
}
Sugerencia
En el código anterior, las llamadas a HasKey
y HasOne
se han agrupado en un generador anidado. Los constructores anidados eliminan la necesidad de llamar a Entity<>()
varias veces para el mismo tipo de entidad, pero son equivalentes funcionalmente a llamar a Entity<>()
múltiples veces.
Se requiere uno a uno sin eliminación en cascada
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
Por convención, las relaciones necesarias se configuran para eliminar en cascada. Esto se debe a que el dependiente no puede existir en la base de datos una vez eliminada la entidad principal. La base de datos se puede configurar para generar un error, normalmente bloqueando la aplicación, en lugar de eliminar automáticamente las filas dependientes que ya no pueden existir. Esto requiere alguna configuración:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.OnDelete(DeleteBehavior.Restrict);
}
Autorreferencia de uno a uno
En todos los ejemplos anteriores, el tipo de entidad principal era diferente del tipo de entidad dependiente. Esto no tiene que ser el caso. Por ejemplo, en los tipos siguientes, cada uno Person
está opcionalmente relacionado con otro Person
.
public class Person
{
public int Id { get; set; }
public int? HusbandId { get; set; } // Optional foreign key property
public Person? Husband { get; set; } // Optional reference navigation to principal
public Person? Wife { get; set; } // Reference navigation to dependent
}
Esta relación se detecta por convención. En los casos en los que las navegaciones, la clave externa o la naturaleza obligatoria/opcional de la relación no se detectan por convención, estas cosas se pueden configurar explícitamente. Por ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOne(e => e.Husband)
.WithOne(e => e.Wife)
.HasForeignKey<Person>(e => e.HusbandId)
.IsRequired(false);
}
Nota:
Para las relaciones de autorreferencia uno a uno, dado que los tipos de entidad principal y dependiente son los mismos, especificar qué tipo contiene la clave externa no aclara el lado dependiente. En este caso, la navegación especificada en HasOne
apunta de dependiente a principal, y la navegación especificada en WithOne
apunta de principal a dependiente.