Update many to many Entity Framework c #

3

I'm having trouble updating a record with entityframework, I'll tell you the whole structure below. In short, I have a register of artists, where these artists are related to categories.

entities:

Artist: one-to-one relationship with address
many-to-many relationship with categories

public class Artista
    {

        public int ArtistaId { get; set; }
        public string Nome { get; set; }
        public string Email { get; set; }
        public string Site { get; set; }
        public string Descricao { get; set; }

        public virtual Endereco Endereco { get; set; }

        public DateTime DataCadastro { get; set; }
        public DateTime DataAtualizacao { get; set; }

        public virtual ICollection<ArtistaCategoria> ArtistaCategoria { get; set; }
    }

public class Categoria
    {
        public Categoria()
        {
        }

        public int CategoriaId { get; set; }

        public string Nome { get; set; }

        public virtual ICollection<ArtistaCategoria> ArtistaCategoria { get; set; }
    }

public class ArtistaCategoria
    {
        public int ArtistaCategoriaId { get; set; }
        public int ArtistaId { get; set; }
        public int CategoriaId { get; set; }

        public virtual Artista Artista { get; set; }
        public virtual Categoria Categoria { get; set; }
    }

public class Endereco
    {

        public Endereco()
        {
            Municipio = new Municipio();
        }
        public int EnderecoId { get; set; }
        public string Logradouro { get; set; }
        public string Numero { get; set; }
        public string Bairro { get; set; }
        public string Cep { get; set; }
        public int MunicipioId { get; set; }
        public virtual Municipio Municipio { get; set; }

    }

public class Municipio
    {
        public Municipio()
        {
        }

        public int MunicipioId { get; set; }

        public string Nome { get; set; }

        public string Cep { get; set; }

    }

Fluent API Configuration

public class ArtistaConfiguration : EntityTypeConfiguration<Artista>
    {
        public ArtistaConfiguration()
        {
            HasKey(a => a.ArtistaId);

            Property(a => a.Nome)
                .IsRequired();

            Property(a => a.Email)
                .HasMaxLength(150);

        }


public class EnderecoConfiguration : EntityTypeConfiguration<Endereco>
    {
        public EnderecoConfiguration()
        {
            HasKey(x => x.EnderecoId);
            HasRequired(m => m.Municipio)
                .WithMany()
                .HasForeignKey(m => m.MunicipioId);

            Property(m => m.Cep)
                .IsFixedLength()
                .HasMaxLength(9)
                .HasColumnType("char");

        }
    }

When editing the category and artist relationship, an error is generated.

  

Attaching an entity of type 'ShowFacil.Domain.Entities.Artist' failed   because another entity of the same type already has the same primary   key value. This can happen when using the 'Attach' method or setting   the state of an entity to 'Unchanged' or 'Modified' if any entities in   the graph has conflicting key values. This may be because some   entities are new and have not received database-generated key   values. In this case use the 'Add' method or the 'Added' entity state   to track the graph and then set the state of non-new entities to   'Unchanged' or 'Modified' as appropriate.

Here is the update code:

public void Update(Artista obj, string[] arrayCategoria)
        {
            AtualizaEndereco(obj);
            ValidaCategorias(obj, arrayCategoria);
            Db.Entry(obj).State = EntityState.Modified; << ERRO ACONTECE AQUI
            Db.SaveChanges();
        }

private void AtualizaEndereco(Artista artista)
    {

        if (artista.Endereco != null)
        {
            var endereco = artista.Endereco;

            if (artista.Endereco.MunicipioId != 0)
            {
                var municipio = Db.Municipios.FirstOrDefault(x => x.MunicipioId == artista.Endereco.MunicipioId);
                endereco.Municipio = municipio;

                if (endereco.EnderecoId != 0)
                {
                    Db.Entry(endereco).State = EntityState.Modified;
                }
                else
                {
                    Db.Enderecos.Add(endereco);
                }

                artista.Endereco = endereco;
            }

        }

    }


    private void AtualizarCategorias(Artista artista, string[] categorias)
        {
            var artistaAtual = Db.Artistas
                .FirstOrDefault(a => a.ArtistaId == artista.ArtistaId);

            List<Categoria> categoriasSelecionadas = new List<Categoria>();
            if (categorias != null)
            {
                foreach (var cat in categorias)
                {
                    categoriasSelecionadas.Add(Db.Categorias.Find(int.Parse(cat)));
                }
            }
var categoriasOriginais = Db.ArtistaCategoria.Where(at => at.ArtistaId == artista.ArtistaId).ToList();
            foreach (var item in categoriasOriginais)
            {
                Db.ArtistaCategoria.Remove(item);
                Db.SaveChanges();
            }

            foreach (var categoria in categoriasSelecionadas)
            {
                var artistaCategoria = new ArtistaCategoria
                {
                    Artista = artistaAtual,
                    Categoria = categoria
                };

                Db.ArtistaCategoria.Add(artistaCategoria);
                Db.SaveChanges();
            }

        }
    
asked by anonymous 12.02.2016 / 20:02

1 answer

4

This error is very common, especially just because you are learning Entity Framework now.

When doing this:

var artistaAtual = Db.Artistas
            .FirstOrDefault(a => a.ArtistaId == artista.ArtistaId);

You're loading the same artist twice. As an observable collection, the Entity Framework gets lost by defining only the entry to be updated.

To avoid this, use AsNoTracking() , indicating to the Entity Framework that it should not observe the second collection, like this:

var artistaAtual = Db.Artistas.AsNoTracking()
            .FirstOrDefault(a => a.ArtistaId == artista.ArtistaId);

As you are using an artist detached from the context, this obviously can not be used, or the context will find that artistaAtual is a new artist, just because he is not observing this record:

            var artistaCategoria = new ArtistaCategoria
            {
                Artista = artistaAtual,
                Categoria = categoria
            };

Switch to:

            var artistaCategoria = new ArtistaCategoria
            {
                Artista = artista,
                Categoria = categoria
            };

It may be necessary to warn the context that the object exists and must be observed:

Db.Artistas.Attach(artista);

Therefore:

    public void Update(Artista obj, string[] arrayCategoria)
    {
        Db.Artistas.Attach(artista);
        AtualizaEndereco(obj);
        ValidaCategorias(obj, arrayCategoria);
        Db.Entry(obj).State = EntityState.Modified;
        Db.SaveChanges();
    }
    
12.02.2016 / 20:09