Tengo problemas de direccionamiento indirecto al intentar configurar la API de Fluent para una propiedad que tiene una sola relación de uno a uno, así como una relación de uno a muchos con la misma entidad. Por ejemplo:
public class Person { public int Id { get; set; } public int PrimaryNameId { get; set; } public NameInfo PrimaryName { get; set; } // one-to-one public IList<NameInfo> Names { get; set; } // one-to-many } public class NameInfo { public int Id { get; set; } public int PersonId { get; set; } public Person Person { get; set; } public string Name { get; set; } ... }Estoy tratando de capturar la relación en la que una persona puede tener muchos nombres pero, en la mayoría de los casos, solo me interesa su "Nombre principal". Preferiría no tener una columna colgante en la tabla NameInfo para IsPrimary . Esa columna terminará siendo NULO/FALSO para >90% de los registros.
Cuando traté de configurar manualmente Fluent API para esto
**Configuration on Person Entity** builder.HasOne(c => c.PrimaryName) .WithOne() .HasForeignKey<Person>(c => c.PrimaryNameId) .OnDelete(DeleteBehavior.Restrict) .IsRequired(); builder.HasMany(c => c.Names) .WithOne(n => n.Person) .HasForeignKey(n => n.PersonId);parece que existen restricciones de clave de índice externo que apuntan entre sí, de modo que falla la inicialización de la base de datos. Para agregar un NameInfo, necesito el PersonId, pero para agregar una Persona, necesito un NameInfo Id existente (para el PrimaryNameId requerido -> Nombre principal).
Relacionalmente, ha creado un catch-22 que no tiene nada que ver con EF. En cuanto a la tabla, espera tener:
Person PersonId [PK Not NULL] PrimaryNameId [FK Not NULL]y
Name NameId [PK Not NULL] PersonId [FK Not NULL]Algo tiene que ceder porque no se puede insertar uno antes del otro.
El problema de tratar de desnormalizar de esta manera a nivel de objeto, para tener referencias de "Nombres" y "NombrePrincipal" es que al tener un ID de NombrePrincipal en su Persona, no hay forma de hacer cumplir que El registro de Nombre apuntado por NombrePrincipal es realmente asociado a esa Persona. IsPrimaryName no es una opción muy confiable por la misma razón, no hay forma de hacer cumplir que dos o más registros no terminen con IsPrimaryName = True. Solo puede hacer suposiciones y ejecutar verificaciones de validación de datos para protegerse contra combinaciones no válidas después del hecho.
Cuando se trata de relaciones 1 a 1, la razón para hacer esto debería ser tener un beneficio en el rendimiento. Los datos extraídos de 1 a 1 deberían ser necesarios con poca frecuencia y/o costosos de recuperar. Si un cliente debe tener un conjunto de valores de nombre y puede tener nombres adicionales, entonces la solución adecuada sería:
public class Person { public int Id { get; set; } public string Name { get; set; } // ... additional name-specific fields. public virtual ICollection<AdditionalName> AdditionalNames { get; set; } // one-to-many }Los detalles de nombre requeridos no son costosos, y lo más probable es que se usen o sean útiles la mayor parte del tiempo. No hay ningún beneficio en intentar normalizarlos en una tabla NameInfo simplemente porque es posible que una Persona tenga nombres adicionales. En lugar de intentar normalizar a una tabla NameInfo que tiene dos propósitos (un nombre requerido y nombres adicionales opcionales), recomendaría simplemente crear una tabla AdditionalName para los nombres adicionales opcionales.