Update Many to Many Entity Framework c#

Asked

Viewed 1,002 times

4

I am having difficulty updating a record with entityframework, I will inform the whole structure below. In short, I have a register of artists, where these artists are related to categories.

entities:

Artist: relationship one to one with address
many relationship to many 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; }

    }

Configuration Fluent API

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 other 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 have Conflicting key values. This may be because some entities are new and have not yet 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.

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

        }

1 answer

4


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

In doing this:

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

You’re carrying the same artist twice. As an observable collection, the Entity Framework is lost by setting only the entry to be updated.

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

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

Since you’re using a featured artist from context, this obviously can’t be used, or context will find that artistaAtual is a new artist, precisely because it 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 should 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();
    }
  • Okay, no mistake, but now always register a new artist..

  • 1

    'Cause you’re wearing it Add. Add always adds a new artist. Let to call the exchange of State outside the category validation method.

  • did not understand... Leave to call the State exchange outside the method of validation of categories.

  • I updated the answer.

  • Keeps adding a new artist...

  • Can you tell me after which SaveChanges this duplicate insertion occurs?

  • From saveChanges after var artistCategory = new Artistacategoria { Artist = artist, Category = category };

  • 1

    I updated it once again.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.