Complex Entity Framework Update

Asked

Viewed 249 times

3

Good morning, I have asked a similar question, I am trying to complement this see with more information and starting from 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 address entity should be optional, during registration I can inform the address or not.

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

        }
    }

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, works correctly and does not generate any error, but when I edit this registration to add 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 an Unexpected number of Rows (0). Entities may have been modified or Deleted Since entities Were Loaded. See http://go.microsoft.com/fwlink/? Linkid=472540 for information on understanding and Handling optimistic concurrency exceptions.

As already mentioned 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 that I have totally lost control of the application. I’m totally lay with EF, I’m getting beaten up to do things "idiots" sometimes things that were working stop working without much explanation, this is an application I’m doing to study and I can’t get out of the register, when one part runs another part stops working...

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

  • 1

    I understand what you are going through. Normally the transition is not very simple, but it is important not to guess how to do things. I will answer.

1 answer

2


If the modeling is 0 or 1 address for an artist, then your modeling is incorrect. Do it this way:

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

No need to use Entity Type Configurations.

I don’t understand what it 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’s 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 don’t know if this address is coming properly filled in, but what is certain is that this code will not work.

Try to take a test hard coded like the 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();
    }
  • It had not put the "Artistaid" in the entity address, because the idea was to use the "Endereco" for several other entities, ex. customers, suppliers, etc., they would all have an address and be represented by this entity...

  • I registered with the following code: var municipio = Db.Municipios.First(); artist. Address = new Address { Street street = "Test street", Number = "123", Neighborhood = "Test neighborhood", Zip = "12345-678", Municipality = municipality, Municipality = municipality.Municipality }; Db.Set<Artist>(). Add(artist); Db.Savechanges(); but when editing the register the address is not changed. Db.Entry(artist). State = Entitystate.Modified;

  • Show me a course?

  • I’m writing a course. If you’re interested, call me at the chat for a chat. About the code placed in comment, if the entity already exists, you do not use Add. Uses the modification of State, as per my reply.

  • Yes, the entity already exists, in this case I used Db.Entry(artist). State = Entitystate.Modified; the artist’s data were changed, but the address was not...

  • Ah, yes. I think you’ll need to do the Add of the address then. The reasoning is the same. I will change the answer.

  • About the course I have interest yes, I am looking for the chat here.. :/

  • so it worked, but in this case I do not update the Artist, only the address.. how do I update everything, artist and address? I tried to do Db.Entry(artist). State = Entitystate.Modified; after updating the address, but an error is generated..

  • Then that’s another question with the specific error.

  • Okay, just one more question, about Dataannotations, do you find it more interesting to use Dataannotations in the domain class? better than using Fluent api to set up?

  • Much better. Setup is decentralized and easier to check.

Show 6 more comments

Browser other questions tagged

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