Entity Framework - Doppelter Eintrag '1' für Schlüssel 'PRIMARY' "
Wenn ich unter Verwendung von MySql DB und Entity Framework versuche, Daten einzufügen, die eine Liste von untergeordneten Daten enthalten, erhalte ich den folgenden Fehler: InnerException = {"Doppelter Eintrag '1' für Schlüssel 'PRIMARY'"}
Hier ist ein Bild meiner Tabellen: https://i.stack.imgur.com/bAnVy.png
Das sind meine Models:
public class Etapa
{
public int Id { get; set; }
public string Descricao { get; set; }
[Column("ativo", TypeName = "bit")]
public bool Ativo { get; set; }
[Column("finalizadora", TypeName = "bit")]
public bool Finalizadora { get; set; }
public List<EtapaVinculada> ListaEtapaVinculada { get; set; }
}
[Table("etapa_vinculada")]
public class EtapaVinculada
{
public int Id { get; set; }
[Column("id_etapa_pai")]
public int EtapaPaiId { get; set; }
public Etapa EtapaPai { get; set; }
[Column("id_etapa_filha")]
public int EtapaFilhaId { get; set; }
public Etapa EtapaFilha { get; set; }
public string Descricao { get; set; }
}
Etapas Kontexte sind hier:
public class ContextoEtapa : Contexto
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Etapa>().HasMany(x => x.ListaEtapaVinculada).WithOne(y => y.EtapaPai).HasForeignKey(x => x.EtapaPaiId);
}
public async Task Adicionar(Etapa registro)
{
await AddAsync(registro);
await SaveChangesAsync();
}
}
Wenn ich die Tabellen in DB manuell fülle, kann ich beim Debuggen meines Kontexts sehen, dass mein Etapa-Objekt gefüllt ist und die Eigenschaft ListEtapaVinculada ebenfalls korrekt gefüllt ist.
Das Problem tritt auf, wenn das mit der Liste von EtapaVinculada gefüllte Etapa-Objekt mithilfe der Add-Methode in die Datenbank eingefügt wird. Es scheint mir, dass ich ein falsches Mapping durchgeführt habe, da es den Eindruck erweckt, dass Entity versucht, den Etapa-Datensatz zweimal hintereinander einzufügen, was in den doppelten Schlüsselfehler fällt.
Das automatische Inkrement funktioniert. Wenn ich versuche, ein Objekt wie folgt zu speichern:
{
Etapa etapa = new Etapa();
etapa.Descricao = "test";
etapa.Ativo = true;
etapa.Finalizadora = true;
etapa.ListaEtapaVinculada = new List<EtapaVinculada>(); // Without itens
using (var context = new ContextoEtapa())
{
await context.Etapa.AddAsync(etapa);
await context.SaveChangesAsync();
}
}
Aber wenn ich so etwas mache:
{
Etapa etapaFilha = null;
using (var context = new ContextEtapa())
{
etapaFilha = await context.Etapa.Where(x => x.Id == 666).First();
}
Etapa etapa = new Etapa();
etapa.Descricao = "test";
etapa.Ativo = true;
etapa.Finalizadora = true;
etapa.ListaEtapaVinculada = new List<EtapaVinculada>();
EtapaVinculada etapaVinculada = new EtapaVinculada();
etapaVinculada.EtapaPaiId = etapa.Id;
etapaVinculada.EtapaPai = etapa;
etapaVinculada.EtapaFilhaId = etapaFilha.Id;
etapaVinculada.EtapaFilha = etapaFilha;
etapa.listaEtapaVinculada.Add(etapaVinculada);
using (var context = new ContextoEtapa())
{
await context.Etapa.AddAsync(etapa);
await context.SaveChangesAsync();
}
}
Jetzt habe ich die Fehler des doppelten Schlüssels. Es scheint mir, dass EF versucht, 2x Etapa-Objekt einzufügen. Wenn das richtige Etapa einfügt, fügen Sie alle Elemente von ListaEtapaVinculada ein.
Antworten
Ich denke, das Problem ist, wenn Sie versuchen, eine Instanz des Objekts und eine ID gleichzeitig zuzuweisen, versuchen Sie, die folgende Codezeile zu kommentieren:
{
Etapa etapaFilha = null;
using (var context = new ContextEtapa())
{
etapaFilha = await context.Etapa.Where(x => x.Id == 666).First();
}
Etapa etapa = new Etapa();
etapa.Descricao = "test";
etapa.Ativo = true;
etapa.Finalizadora = true;
etapa.ListaEtapaVinculada = new List<EtapaVinculada>();
EtapaVinculada etapaVinculada = new EtapaVinculada();
// etapaVinculada.EtapaPaiId = etapa.Id; // this is asigned when asign to collection and savechanges
// etapaVinculada.EtapaPai = etapa;
etapaVinculada.EtapaFilhaId = etapaFilha.Id; //
// etapaVinculada.EtapaFilha = etapaFilha; this is duplicate
etapa.listaEtapaVinculada.Add(etapaVinculada);
using (var context = new ContextoEtapa())
{
await context.Etapa.AddAsync(etapa);
await context.SaveChangesAsync();
}
}