Queremos usar una relación opcional uno a uno usando Entity Framework Code First. Tenemos dos entidades.
public class PIIUser
{
public int Id { get; set; }
public int? LoyaltyUserDetailId { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public int PIIUserId { get; set; }
public PIIUser PIIUser { get; set; }
}
PIIUserpuede tener un LoyaltyUserDetailpero LoyaltyUserDetaildebe tener un PIIUser. Probamos estas técnicas de enfoque fluido.
modelBuilder.Entity<PIIUser>()
.HasOptional(t => t.LoyaltyUserDetail)
.WithOptionalPrincipal(t => t.PIIUser)
.WillCascadeOnDelete(true);
Este enfoque no creó LoyaltyUserDetailIduna clave externa en la PIIUserstabla.
Después de eso, probamos el siguiente código.
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(t => t.PIIUser)
.WithRequiredDependent(t => t.LoyaltyUserDetail);
Pero esta vez EF no creó ninguna clave externa en estas 2 tablas.
¿Tiene alguna idea para este tema? ¿Cómo podemos crear una relación opcional uno a uno utilizando la api fluida del marco de entidad?
fuente

WithOptional? ¿Cuál es la diferencia conWithRequiredDependentyWithRequiredOptional?Simplemente haz como si tuvieras una relación de uno a muchos entre ellos
LoyaltyUserDetailyPIIUsertu mapeo debería serEF debería crear todas las claves externas que necesita y simplemente no le importa WithMany .
fuente
Hay varios problemas con su código.
Una relación 1: 1 es: PK <-PK , donde un lado PK es también un FK, o PK <-FK + UC , donde el lado FK no es PK y tiene UC. Su código muestra que tiene FK <-FK , ya que define ambos lados para tener un FK, pero eso está mal. Recon
PIIUseres el lado PK yLoyaltyUserDetailes el lado FK. Esto significaPIIUserque no tiene un campo FK, pero loLoyaltyUserDetailtiene.Si el 1: 1 es opcional, el lado FK debe tener al menos 1 campo anulable.
pswg anterior respondió a su pregunta, pero cometió un error de que también definió un FK en PIIUser, que por supuesto es incorrecto como describí anteriormente. Así que defina el campo FK anulable en
LoyaltyUserDetail, defina el atributo enLoyaltyUserDetailpara marcarlo como el campo FK, pero no especifique un campo FK enPIIUser.Obtiene la excepción que describe arriba debajo de la publicación de pswg, porque ningún lado es el lado PK (final del principio).
EF no es muy bueno en 1: 1 ya que no puede manejar restricciones únicas. No soy un experto en Code primero, así que no sé si es capaz de crear una UC o no.
(editar) por cierto: A 1: 1 B (FK) significa que solo hay 1 restricción FK creada, en el objetivo de B apuntando al PK de A, no a 2.
fuente
public class User { public int Id { get; set; } public int? LoyaltyUserId { get; set; } public virtual LoyaltyUser LoyaltyUser { get; set; } } public class LoyaltyUser { public int Id { get; set; } public virtual User MainUser { get; set; } } modelBuilder.Entity<User>() .HasOptional(x => x.LoyaltyUser) .WithOptionalDependent(c => c.MainUser) .WillCascadeOnDelete(false);esto resolverá el problema de REFERENCIA y LLAVES EXTRANJERAS
al ACTUALIZAR o BORRAR un registro
fuente
Intente agregar el
ForeignKeyatributo a laLoyaltyUserDetailpropiedad:public class PIIUser { ... public int? LoyaltyUserDetailId { get; set; } [ForeignKey("LoyaltyUserDetailId")] public LoyaltyUserDetail LoyaltyUserDetail { get; set; } ... }Y la
PIIUserpropiedad:public class LoyaltyUserDetail { ... public int PIIUserId { get; set; } [ForeignKey("PIIUserId")] public PIIUser PIIUser { get; set; } ... }fuente
ForeignKeyatributo a solo un extremo de la relación? es decir, solo enPIIUseroLoyaltyUserDetail.Lo único que resulta confuso con las soluciones anteriores es que la clave principal se define como " Id" en ambas tablas y si tiene una clave principal basada en el nombre de la tabla, no funcionaría, he modificado las clases para ilustrar lo mismo, es decir, la tabla opcional no debería definir su propia clave primaria, sino que debería utilizar el mismo nombre de clave de la tabla principal.
public class PIIUser { // For illustration purpose I have named the PK as PIIUserId instead of Id // public int Id { get; set; } public int PIIUserId { get; set; } public int? LoyaltyUserDetailId { get; set; } public LoyaltyUserDetail LoyaltyUserDetail { get; set; } } public class LoyaltyUserDetail { // Note: You cannot define a new Primary key separately as it would create one to many relationship // public int LoyaltyUserDetailId { get; set; } // Instead you would reuse the PIIUserId from the primary table, and you can mark this as Primary Key as well as foreign key to PIIUser table public int PIIUserId { get; set; } public double? AvailablePoints { get; set; } public int PIIUserId { get; set; } public PIIUser PIIUser { get; set; } }Y luego seguido de
Haría el truco, la solución aceptada no explica claramente esto, y me confundió durante unas horas para encontrar la causa
fuente
Esto no es de utilidad para el póster original, pero para cualquiera que todavía esté en EF6 y necesite que la clave externa sea diferente de la clave principal, aquí se explica cómo hacerlo:
public class PIIUser { public int Id { get; set; } //public int? LoyaltyUserDetailId { get; set; } public LoyaltyUserDetail LoyaltyUserDetail { get; set; } } public class LoyaltyUserDetail { public int Id { get; set; } public double? AvailablePoints { get; set; } public int PIIUserId { get; set; } public PIIUser PIIUser { get; set; } } modelBuilder.Entity<PIIUser>() .HasRequired(t => t.LoyaltyUserDetail) .WithOptional(t => t.PIIUser) .Map(m => m.MapKey("LoyaltyUserDetailId"));Tenga en cuenta que no puede usar el
LoyaltyUserDetailIdcampo porque, por lo que puedo decir, solo se puede especificar usando la API fluida. (He probado tres formas de hacerlo usando elForeignKeyatributo y ninguna funcionó).fuente