Entity Framework - Doppelter Eintrag '1' für Schlüssel 'PRIMARY' "

Nov 17 2020

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

henocsalinas Nov 19 2020 at 06:27

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();
    }
}