Entity Framework - Duplicar entrada '1' para a chave 'PRIMARY' "
Usando MySql DB e Entity Framework, ao tentar inserir um dado que contenha uma lista de dados filho, recebo este erro: InnerException = {"Entrada duplicada '1' para a chave 'PRIMARY'"}
Aqui está uma imagem das minhas mesas: https://i.stack.imgur.com/bAnVy.png
Estas são minhas modelos:
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; }
}
Os contextos da Etapa estão aqui:
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();
}
}
Preenchendo manualmente as tabelas no DB, ao depurar meu contexto posso ver que meu objeto Etapa está preenchido e a propriedade ListEtapaVinculada também está preenchida, corretamente.
O problema ocorre quando o objeto Etapa preenchido com sua lista de EtapaVinculada vai ser inserido no banco de dados através do método Add. Parece-me que fiz algum mapeamento errado, pois dá a impressão que a Entidade tenta inserir 2x o registro da Etapa seguidos, caindo no erro de chave duplicada.
O incremento automático está funcionando. Se eu tentar salvar um objeto como este:
{
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();
}
}
Mas, se eu fizer algo assim:
{
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();
}
}
Agora recebo os erros de chave duplicada. Parece-me que EF está tentando inserir o objeto 2x Etapa, quando o correto é inserir Etapa, então inserir todos os itens de ListaEtapaVinculada.
Respostas
Acho que o problema é ao tentar atribuir uma instância do objeto e um id ao mesmo tempo, tente comentar na seguinte linha de código:
{
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();
}
}