property name hasforeignkey framework foreign first data column code entity-framework ef-code-first

entity framework - name - Código EF Primera clave externa sin propiedad de navegación



fluent api entity framework foreign key (3)

Aunque esta publicación es para Entity Framework no Entity Framework Core , podría ser útil para alguien que quiera lograr lo mismo utilizando Entity Framework Core (estoy usando V1.1.2).

No necesito propiedades de navegación (aunque son agradables) porque estoy practicando DDD y quiero que Parent e Child sean dos raíces agregadas separadas. Quiero que puedan hablar entre ellos a través de una clave externa, no a través de las propiedades de navegación de Entity Framework específicas de la infraestructura.

Todo lo que tienes que hacer es configurar la relación en un lado.

public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { ...... builder.Entity<Parent>(e => { e.HasKey(x => x.Id); e.ToTable("Parent"); }); builder.Entity<Child>(e => { e.HasKey(x => x.Id); e.Property(x => x.ParentId).IsRequired(); e.HasOne<Parent>() .WithMany() .HasForeignKey(x => x.ParentId); e.ToTable("Child"); }); ...... } }

Estoy dando ejemplos sobre cómo configurar las propiedades de la entidad también, pero la más importante aquí es HasOne<> , WithMany() y HasForeignKey() .

Espero eso ayude.

Digamos que tengo las siguientes entidades:

public class Parent { public int Id { get; set; } } public class Child { public int Id { get; set; } public int ParentId { get; set; } }

¿Cuál es la primera sintaxis de API fluida del código para exigir que ParentId se cree en la base de datos con una restricción de clave externa en la tabla Padres, sin la necesidad de tener una propiedad de navegación ?

Sé que si agrego una propiedad de navegación de padre a hijo, puedo hacer esto:

modelBuilder.Entity<Child>() .HasRequired<Parent>(c => c.Parent) .WithMany() .HasForeignKey(c => c.ParentId);

Pero no quiero la propiedad de navegación en este caso particular.


Con EF Code First Fluent API es imposible. Siempre necesita al menos una propiedad de navegación para crear una restricción de clave externa en la base de datos.

Si está utilizando Code First Migrations, tiene la opción de agregar una nueva migración basada en código en la consola del administrador de paquetes ( add-migration SomeNewSchemaName ). Si cambió algo con su modelo o mapeo, se agregará una nueva migración. Si no add-migration -IgnoreChanges SomeNewSchemaName nada, forza una nueva migración usando add-migration -IgnoreChanges SomeNewSchemaName . La migración solo contendrá métodos vacíos Up y Down en este caso.

Luego puede modificar el método Up añadiéndole lo siguiente:

public override void Up() { // other stuff... AddForeignKey("ChildTableName", "ParentId", "ParentTableName", "Id", cascadeDelete: true); // or false CreateIndex("ChildTableName", "ParentId"); // if you want an index }

Al ejecutar esta migración ( update-database en la consola de administración de paquetes) se ejecutará una declaración SQL similar a esta (para SQL Server):

ALTER TABLE [ChildTableName] ADD CONSTRAINT [FK_SomeName] FOREIGN KEY ([ParentId]) REFERENCES [ParentTableName] ([Id]) CREATE INDEX [IX_SomeName] ON [ChildTableName] ([ParentId])

Alternativamente, sin migraciones, podría simplemente ejecutar un comando SQL puro usando

context.Database.ExecuteSqlCommand(sql);

donde context es una instancia de su clase de contexto derivado y sql es solo el comando SQL anterior como cadena.

Tenga en cuenta que con todo esto EF no tiene ni idea de que ParentId es una clave externa que describe una relación. EF lo considerará solo como una propiedad escalar ordinaria. De alguna manera, todo lo anterior es solo una forma más complicada y lenta en comparación con solo abrir una herramienta de administración de SQL y agregar la restricción manualmente.


Una pequeña sugerencia para aquellos que desean usar DataAnotations y no quieren exponer la propiedad de navegación - use protected

public class Parent { public int Id { get; set; } } public class Child { public int Id { get; set; } public int ParentId { get; set; } protected virtual Parent Parent { get; set; } }

Eso es todo: la clave externa con cascade:true después Add-Migration se haya creado Add-Migration .