ventajas tutorial que framework foreign first example español ejemplo desventajas code c# entity-framework ef-code-first one-to-one ef-fluent-api

c# - tutorial - entity framework ventajas y desventajas



Relación opcional de uno a uno utilizando Entity Framework Fluent API (6)

EF Code First admite relaciones 1:1 y 1:0..1 . Este último es lo que está buscando ("uno a cero o uno").

Sus intentos de hablar con fluidez dicen que es necesario en ambos extremos en un caso y opcional en ambos en el otro.

Lo que necesita es opcional en un extremo y requerido en el otro.

Aquí hay un ejemplo del primer libro del Código de programación de EF

modelBuilder.Entity<PersonPhoto>() .HasRequired(p => p.PhotoOf) .WithOptional(p => p.Photo);

La entidad PersonPhoto tiene una propiedad de navegación llamada PhotoOf que apunta a un tipo de Person . El tipo Person tiene una propiedad de navegación llamada Photo que apunta al tipo PersonPhoto .

En las dos clases relacionadas, utiliza la clave principal de cada tipo, no las claves externas . es decir, no usará las propiedades LoyaltyUserDetailId o PIIUserId . En cambio, la relación depende de los campos Id de ambos tipos.

Si está utilizando la API con fluidez como se LoyaltyUser.Id anteriormente, no necesita especificar LoyaltyUser.Id como clave foránea, EF lo resolverá.

Así que sin tener tu código para probarme (odio hacer esto de mi cabeza) ... traduciría esto en tu código como

public class PIIUser { public int Id { get; set; } public LoyaltyUserDetail LoyaltyUserDetail { get; set; } } public class LoyaltyUserDetail { public int Id { get; set; } public double? AvailablePoints { get; set; } public PIIUser PIIUser { get; set; } } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<LoyaltyUserDetail>() .HasRequired(lu => lu.PIIUser ) .WithOptional(pi => pi.LoyaltyUserDetail ); }

Es decir, se requiere la propiedad PIIUser de LoyaltyUserDetail y la propiedad LoyaltyUserDetail de LoyaltyUserDetail es opcional.

Puedes comenzar desde el otro extremo:

modelBuilder.Entity<PIIUser>() .HasOptional(pi => pi.LoyaltyUserDetail) .WithRequired(lu => lu.PIIUser);

que ahora dice que la propiedad LoyaltyUserDetail de LoyaltyUserDetail es opcional y se requiere la propiedad PIIUser de PIIUser .

Siempre debe usar el patrón HAS / WITH.

HTH y FWIW, las relaciones uno a uno (o uno a cero / uno) son una de las relaciones más confusas para configurar primero en el código, ¡por lo que no estás solo! :)

Queremos utilizar una relación opcional de uno a uno utilizando 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; } }

PIIUser puede tener un LoyaltyUserDetail pero LoyaltyUserDetail debe tener un PIIUser . Probamos estas técnicas de acercamiento fluido.

modelBuilder.Entity<PIIUser>() .HasOptional(t => t.LoyaltyUserDetail) .WithOptionalPrincipal(t => t.PIIUser) .WillCascadeOnDelete(true);

Este enfoque no creó la clave externa PIIUsers en la tabla PIIUsers .

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 foránea en estas 2 tablas.

¿Tienes alguna idea para este problema? ¿Cómo podemos crear una relación opcional de uno a uno utilizando la API de Entity con fluidez?


Hay varias cosas mal con su código.

Una relación 1: 1 es: PK <-PK , donde un lado PK también es un FK, o PK <-FK + UC , donde el lado FK no es PK y tiene un UC. Su código muestra que tiene FK <-FK , ya que define que ambos lados tienen un FK, pero eso está mal. PIIUser es el lado PK y LoyaltyUserDetail es el lado FK. Esto significa que PIIUser no tiene un campo FK, pero LoyaltyUserDetail hace LoyaltyUserDetail .

Si la relación 1: 1 es opcional, el lado FK debe tener al menos 1 campo anulable.

pswg de arriba contestó tu pregunta, pero cometió un error al definir también un FK en PIIUser, lo cual es, por supuesto, incorrecto como describí anteriormente. Así que defina el campo NULL FK en LoyaltyUserDetail , defina el atributo en LoyaltyUserDetail para marcarlo como el campo FK, pero no especifique un campo FK en PIIUser .

Obtiene la excepción que describe arriba debajo de la publicación de pswg, porque ningún lado es el lado PK (extremo principal).

EF no es muy bueno en 1: 1 ya que no es capaz de manejar restricciones únicas. Primero no soy experto en Código, por lo que no sé si puede crear una UC o no.

(edit) btw: A 1: 1 B (FK) significa que hay solo 1 restricción de FK creada, en el objetivo de B apuntando al PK de A, no a 2.


Intente agregar el atributo ForeignKey a la propiedad LoyaltyUserDetail :

public class PIIUser { ... public int? LoyaltyUserDetailId { get; set; } [ForeignKey("LoyaltyUserDetailId")] public LoyaltyUserDetail LoyaltyUserDetail { get; set; } ... }

Y la propiedad PIIUser :

public class LoyaltyUserDetail { ... public int PIIUserId { get; set; } [ForeignKey("PIIUserId")] public PIIUser PIIUser { get; set; } ... }


Lo único que confunde con las soluciones anteriores es que la clave principal se define como " Id" en ambas tablas y si tiene 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 debe definir su propia clave primaria sino que debe usar 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 por

modelBuilder.Entity<PIIUser>() .HasOptional(pi => pi.LoyaltyUserDetail) .WithRequired(lu => lu.PIIUser);

Haría el truco, la solución aceptada no puede explicar esto claramente, y me desanimó durante unas horas para encontrar la causa


Simplemente haga como si tuviera una relación de uno a muchos entre LoyaltyUserDetail y PIIUser por lo que su mapeo debería ser

modelBuilder.Entity<LoyaltyUserDetail>() .HasRequired(m => m.PIIUser ) .WithMany() .HasForeignKey(c => c.LoyaltyUserDetailId);

EF debe crear todas las claves foráneas que necesites y ¡simplemente no te importa WithMany !


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 en REFERENCIA y LLAVES EXTRANJERAS

al ACTUALIZAR o BORRAR un registro