Sto riscontrando un errore durante il tentativo di creare un database dal suo modello utilizzando Entity Framework Core 2.0.1 e il provider npgsql 2.0.1.
La descrizione dell'errore è:
"vincolo « FK_PiezasStockExterno_ContenedoresDocumentos_IdContenedorDocume »per la relazione « PiezasStockExterno »esiste già.
Non ho alcuna chiamata a Database.EnsureCreated () poiché sono consapevole che causa problemi durante la migrazione e il database viene eliminato prima quindi mi assicuro che non esista. Succede usando i seguenti comandi o chiamando Database.EnsureCreated (). Quale potrebbe essere il vero problema?
Script di errore:
CREATE TABLE "public"."PiezasStockExterno"
(
"Id" serial NOT NULL,
"IdContenedorDocumentosPieza" int4 NULL,
"IdContenedorDocumentosVehiculo" int4 NULL,
CONSTRAINT "PK_PiezasStockExterno" PRIMARY KEY ("Id"),
CONSTRAINT "FK_PiezasStockExterno_ContenedoresDocumentos_IdContenedorDocumentosPieza"
FOREIGN KEY ("IdContenedorDocumentosPieza")
REFERENCES "public"."ContenedoresDocumentos" ("Id") ON DELETE RESTRICT,
CONSTRAINT "FK_PiezasStockExterno_ContenedoresDocumentos_IdContenedorDocumentosVehiculo"
FOREIGN KEY ("IdContenedorDocumentosVehiculo")
REFERENCES "public"."ContenedoresDocumentos" ("Id") ON DELETE RESTRICT
)
Modelli:
[Table("PiezasStockExterno", Schema = "public")]
public class PiezaStockExterno
{
[Key]
public int Id { get; set; }
public int? IdContenedorDocumentosPieza { get; set; }
[ForeignKey("IdContenedorDocumentosPieza")]
public virtual ContenedorDocumentos ContenedorDocumentosPieza { get; set; }
public int? IdContenedorDocumentosVehiculo { get; set; }
[ForeignKey("IdContenedorDocumentosVehiculo")]
public virtual ContenedorDocumentos ContenedorDocumentosVehiculo { get; set; }
}
[Table("ContenedoresDocumentos", Schema = "public")]
public class ContenedorDocumentos
{
[Key]
public int Id { get; set; }
[InverseProperty("ContenedorDocumentos")]
public IList<Imagen> Imagenes { get; set; }
[InverseProperty("ContenedorDocumentos")]
public IList<Foto> Fotos { get; set; }
[InverseProperty("ContenedorDocumentos")]
public IList<Documento> Documentos { get; set; }
[InverseProperty("ContenedorDocumentos")]
public IList<Video> Videos { get; set; }
}
Contesto:
public NContext(DbContextOptions<NContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseNpgsql(ConnectionString, b => b.MigrationsAssembly("WebAPI"));
optionsBuilder.EnableSensitiveDataLogging();
base.OnConfiguring(optionsBuilder);
}
Startup.cs nel progetto WebAPI:
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkNpgsql().AddDbContext<Infrastructure.Data.NContext>();
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver())
.AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
AutoMapperConfig.Initialize();
}
comandi:
dotnet ef migrations add InitialMigration
dotnet ef database update
OR
Database.EnsureCreated()
InitialMigration.cs:
migrationBuilder.CreateTable(
name: "PiezasStockExterno",
schema: "public",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
IdContenedorDocumentosPieza = table.Column<int>(nullable: true),
IdContenedorDocumentosVehiculo = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PiezasStockExterno", x => x.Id);
table.ForeignKey(
name: "FK_PiezasStockExterno_ContenedoresDocumentos_IdContenedorDocumentosPieza",
column: x => x.IdContenedorDocumentosPieza,
principalSchema: "public",
principalTable: "ContenedoresDocumentos",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_PiezasStockExterno_ContenedoresDocumentos_IdContenedorDocumentosVehiculo",
column: x => x.IdContenedorDocumentosVehiculo,
principalSchema: "public",
principalTable: "ContenedoresDocumentos",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
Sicuramente stai raggiungendo la lunghezza massima dell'identificatore di PostgreSQL di 63 byte con i nomi dei vincoli FK, che dopo il troncamento diventano uno e lo stesso, quindi l'errore già esistente confuso (sebbene si possa vedere che il nome è troncato).
Poiché la specifica del nome del vincolo FK è attualmente possibile solo con Fluent API , è necessario eseguire l'override di OnModelCreating
e aggiungere il seguente codice (utilizzare nomi che abbiano senso per te e che non superino 63 caratteri):
modelBuilder.Entity<PiezaStockExterno>()
.HasOne(e => e.ContenedorDocumentosPieza)
.WithMany()
.HasConstraintName("FK_PiezasStockExterno_IdContenedorDocumentosPieza");
modelBuilder.Entity<PiezaStockExterno>()
.HasOne(e => e.ContenedorDocumentosVehiculo)
.WithMany()
.HasConstraintName("FK_PiezasStockExterno_IdContenedorDocumentosVehiculo");
E nel caso in cui si aggiungano proprietà di navigazione della raccolta inversa, non dimenticare di aggiornare la chiamata WithMany
corrispondente.