Complex Update Entity Framework

3

Good morning, I have already asked a similar question, I am trying to complement this view with more information and starting with the most basic.

I have the following structure:

public class Artista
    {

        public 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 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; }

    }

The entity address must be optional, during the registration I can inform the address or not.

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");

        }
    }

The artist's registration is done as follows:

public void Add(Artista obj)
        {

            ValidaEndereco(obj);

            Db.Set<Artista>().Add(obj);
            Db.SaveChanges();

        }

private void ValidaEndereco(Artista artista)
        {
            var endereco = artista.Endereco;

            if (string.IsNullOrEmpty(endereco.Logradouro)
                    & string.IsNullOrEmpty(endereco.Numero)
                    & string.IsNullOrEmpty(endereco.Bairro))
            {
                artista.Endereco = null;
            }
            else
            {
                artista.Endereco.Municipio = null;
            }



        }

The update:

public void Update(Artista obj)
        {
            AtualizaEndereco(obj);
            Db.Entry(obj).State = EntityState.Modified;
            Db.SaveChanges();

        }

private void AtualizaEndereco(Artista artista)
        {

            var endereco = artista.Endereco;

            if (string.IsNullOrEmpty(endereco.Logradouro)
                    & string.IsNullOrEmpty(endereco.Numero)
                    & string.IsNullOrEmpty(endereco.Bairro))
            {
                artista.Endereco = null;
            }
            else
            {
                artista.Endereco.Municipio = null;
                endereco.Municipio = null;
                Db.Entry(endereco).State = EntityState.Modified;
            }



        }

In this case, when registering an artist and not registering the address, it works correctly and does not generate any errors, however when I edit this register for adding an address the following error is shown:

  

An exception of type   'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException'   occurred in EntityFramework.dll but was not handled in user code

     

Additional information: Store update, insert, or delete statement   affected by an unexpected number of rows (0). Entities may have been   modified or deleted since characters were loaded. See    link for information on   understanding and handling optimistic concurrency exceptions.

As I said in another post, I always programmed with ADO and Stored Procedures, and I always heard that I was wasting time, that Entity Framework has a very big productivity gain, but I feel I totally lost control of the application. I'm totally lay with EF, I'm getting too much to do "idiot" things sometimes things that were working stop working without much explanation, this is an application that I'm doing to study and I can not get out of the register, when one part works another for to function ...

If someone needs the source to verify I can also provide ...

    
asked by anonymous 11.02.2016 / 15:37

1 answer

2

If the modeling is 0 or 1 addresses for an artist, then its modeling is incorrect. Do as follows:

// Repare que retirei os construtores das propriedades de navegação.
// Isto porque eles não são necessários. Toda inicialização de propriedades
// de navegação fica a cargo do Entity Framework. 

public class Artista
{
    [Key]
    public int ArtistaId { get; set; }

    public string Nome { get; set; }
    [EmailAddress]
    public string Email { get; set; }
    public string Site { get; set; }
    [DataType(DataType.MultilineText)]
    public string Descricao { get; set; }

    public virtual Endereco Endereco { get; set; }

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

public class Endereco
{
    // Aqui está o segredo da cardinalidade:
    // A chave primária de endereço também é a chave estrangeira para artista.
    // É a única forma de garantir que um endereço pertence a um, e apenas
    // um artista.
    [Key, ForeignKey("Artista")]
    public int ArtistaId { get; set; }
    public int MunicipioId { get; set; }

    public string Logradouro { get; set; }
    public string Numero { get; set; }
    public string Bairro { get; set; }
    public string Cep { get; set; }

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

public class Municipio
{
    [Key]
    public int MunicipioId { get; set; }

    public string Nome { get; set; }

    public string Cep { get; set; }

    public virtual ICollection<Endereco> Enderecos { get; set; }
}

You do not need to use Entity Type Configurations.

I do not understand what this does:

    private void ValidaEndereco(Artista artista)
    {
        var endereco = artista.Endereco;

        if (string.IsNullOrEmpty(endereco.Logradouro)
                & string.IsNullOrEmpty(endereco.Numero)
                & string.IsNullOrEmpty(endereco.Bairro))
        {
            artista.Endereco = null;
        }
        else
        {
            artista.Endereco.Municipio = null;
        }
    }

But it is important to say that this approach is not good.

So much so that the code that is important makes even less sense:

    private void AtualizaEndereco(Artista artista)
    {
        var endereco = artista.Endereco;

        if (string.IsNullOrEmpty(endereco.Logradouro)
                & string.IsNullOrEmpty(endereco.Numero)
                & string.IsNullOrEmpty(endereco.Bairro))
        {
            artista.Endereco = null;
        }
        else
        {
            artista.Endereco.Municipio = null;
            endereco.Municipio = null;
            Db.Entry(endereco).State = EntityState.Modified;
        }
    }

I do not know if this address is coming correctly filled, but what is certain is that this code will not work.

Try a hard coded test like the one below:

    private void InserirEnderecoHard(Artista artista)
    {
        var municipio = Db.Municipios.First();
        var endereco = new Endereco {
            Logradouro = "Rua de Teste",
            Numero = "123",
            Bairro = "Bairro Teste",
            Cep = "12345-678",
            Municipio = municipio,
            Artista = artista
        };

        Db.Enderecos.Add(endereco);
        Db.SaveChanges();
    }
    
11.02.2016 / 16:00