Fluent Api entering undesirable records

Asked

Viewed 113 times

0

I have the following classes:

Estado.Cs

public class Estado
{
    public Int32 EstadoId { get; set; }
    public Int32 CodigoEstado { get; set; }
    public String Sigla { get; set; }
    public String Nome { get; set; }
    public virtual ICollection<Cidade> CidadeLista { get; set; }        

    public Estado()
    {
        CidadeLista = new List<Cidade>();
    }
}

City.Cs

public class Cidade
{
    public Int32 CidadeId { get; set; }
    public Int32 CodigoEstado { get; set; }
    public Int32 CodigoCidade { get; set; }
    public String Nome { get; set; }

    public Estado Estado { get; set; }
    public virtual ICollection<Endereco> EnderecoLista { get; set; }

    public Cidade()
    {
        EnderecoLista = new List<Endereco>();
    }
}

And the following table maps:

Estadomap.Cs

public class EstadoMap : EntityTypeConfiguration<Estado>
{
    public EstadoMap()
    {
        ToTable("ESTADO");
        HasKey(x => x.EstadoId);

        Property(x => x.EstadoId)
            .HasColumnName("ESTADO_ID")
            .HasColumnOrder(0)
            .IsRequired();

        Property(x => x.CodigoEstado)
            .HasColumnName("CODIGO_ESTADO")
            .HasColumnOrder(1)
            .IsRequired();

        Property(x => x.Sigla)
            .HasColumnName("SIGLA")
            .HasColumnOrder(2)
            .IsRequired()
            .HasMaxLength(2);

        Property(x => x.Nome)
            .HasColumnName("NOME")
            .HasColumnOrder(3)
            .IsRequired()
            .HasMaxLength(30);
    }
}

Cidademap.Cs

public class CidadeMap : EntityTypeConfiguration<Cidade>
{
    public CidadeMap()
    {
        ToTable("CIDADE");
        HasKey(x => x.CidadeId);

        Property(x => x.CidadeId)
            .HasColumnName("CIDADE_ID");

        Property(x => x.Nome)
            .HasColumnName("NOME")
            .IsRequired()
            .HasMaxLength(60);

        Property(x => x.CodigoCidade)
            .HasColumnName("CODIGO_CIDADE")
            //.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }))
            .IsRequired();

        Property(x => x.CodigoEstado)
            .HasColumnName("CODIGO_ESTADO")

            .IsRequired();

        //Relationships
        HasRequired(x => x.Estado)
            .WithMany(x => x.CidadeLista)
            .HasForeignKey(x => x.CodigoEstado);
    }
}

I looked in the bank and the result is as expected, being the column codigo_estado table Estado referenced in the table Cidade like FK.

To populate them, I saved on my machine the IBGE pages with this information and then fed the tables, as code below.

Citieseed

public class CidadeSeed
{
    public static void Seed(TecGasContext context)
    {
        List<Estado> listaEstado = new List<Estado>()
        {
            new Estado {CodigoEstado = 12, Nome = "Acre", Sigla = "AC" },
            new Estado {CodigoEstado = 27, Nome = "Alagoas", Sigla = "AL" },
            new Estado {CodigoEstado = 13, Nome = "Amazonas", Sigla = "AM" },
            new Estado {CodigoEstado = 16, Nome = "Amapá", Sigla = "AP" },
            new Estado {CodigoEstado = 29, Nome = "Bahia", Sigla = "BA" },
            new Estado {CodigoEstado = 23, Nome = "Ceará", Sigla = "CE" },
            new Estado {CodigoEstado = 53, Nome = "Distrito Federal", Sigla = "DF" },
            new Estado {CodigoEstado = 32, Nome = "Espírito Santo", Sigla = "ES" },
            new Estado {CodigoEstado = 52, Nome = "Goiás", Sigla = "GO" },
            new Estado {CodigoEstado = 21, Nome = "Maranhão", Sigla = "MA" },
            new Estado {CodigoEstado = 31, Nome = "Minas Gerais", Sigla = "MG" },
            new Estado {CodigoEstado = 50, Nome = "Mato Grosso do Sul", Sigla = "MS" },
            new Estado {CodigoEstado = 51, Nome = "Mato Grosso", Sigla = "MT" },
            new Estado {CodigoEstado = 15, Nome = "Pará", Sigla = "PA" },
            new Estado {CodigoEstado = 25, Nome = "Paraíba", Sigla = "PB" },
            new Estado {CodigoEstado = 26, Nome = "Pernambuco", Sigla = "PE" },
            new Estado {CodigoEstado = 22, Nome = "Piauí", Sigla = "PI" },
            new Estado {CodigoEstado = 41, Nome = "Paraná", Sigla = "PR" },
            new Estado {CodigoEstado = 33, Nome = "Rio de Janeiro", Sigla = "RJ" },
            new Estado {CodigoEstado = 24, Nome = "Rio Grande do Norte", Sigla = "RN" },
            new Estado {CodigoEstado = 11, Nome = "Rondônia", Sigla = "RO" },
            new Estado {CodigoEstado = 14, Nome = "Roraima", Sigla = "RR" },
            new Estado {CodigoEstado = 43, Nome = "Rio Grande do Sul", Sigla = "RS" },
            new Estado {CodigoEstado = 42, Nome = "Santa Catarina", Sigla = "SC" },
            new Estado {CodigoEstado = 28, Nome = "Sergipe", Sigla = "SE" },
            new Estado {CodigoEstado = 35, Nome = "São Paulo", Sigla = "SP" },
            new Estado {CodigoEstado = 17, Nome = "Tocantis", Sigla = "TO" },
        };


        foreach (var estadoItem in listaEstado)
        {
            var client = new WebClient();
            var content = client.DownloadString(String.Format("{0}{1}{2}", "file:///C:/Projetos/TecGas/CidadesPorEstado/", estadoItem.Sigla, ".html"));

            byte[] bytes = Encoding.Default.GetBytes(content);
            content = Encoding.UTF8.GetString(bytes);

            var document = new HtmlDocument();
            document.LoadHtml(content);

            var htmlContainer =
                    document.DocumentNode.SelectNodes("html/body/div[@id='conteudo']/table[@id='municipios']/tbody/tr");

            foreach (var cidadeItem in htmlContainer)
            {
                var codigoEstado = estadoItem.CodigoEstado;
                Int32 codigoCidade = Convert.ToInt32(cidadeItem.SelectSingleNode("td[@class='codigo']").InnerText);
                var nome = cidadeItem.SelectSingleNode("td[@class='nome']").InnerText;
                Cidade novaCidade = new Cidade
                {
                    CodigoEstado = codigoEstado,
                    CodigoCidade = codigoCidade,
                    Nome = nome,
                    Estado = estadoItem
                };

                try
                {
                    context.Configuration.LazyLoadingEnabled = false;
                    context.Cidade.Add(novaCidade);
                    context.SaveChanges();
                }
                catch (DbEntityValidationException e)
                {
                    StreamWriter writer = new StreamWriter(@"C:\Projetos\TecGas\CidadesPorEstado\Erro.txt");
                    foreach (var eve in e.EntityValidationErrors)
                    {
                        writer.Write(String.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State));

                        foreach (var ve in eve.ValidationErrors)
                        {
                            writer.Write(String.Format("- Property: \"{0}\", Error: \"{1}\"",
                                ve.PropertyName, ve.ErrorMessage));
                        }
                    }
                    writer.Close();
                    throw;
                }
            }
        }
    }
}

Configuration.Cs

internal sealed class Configuration : DbMigrationsConfiguration<TecGas.BackEnd.DataAccess.TecGasContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }

    protected override void Seed(TecGasContext context)
    {
        CidadeSeed.Seed(context);
    }
}

On the table Estado it’s all ok, the inserted fields are exactly the ones I fed the table. Already in the table Cidade to FK codigo_estado is being fed with the column EstadoId. It is not what I wish. I would like that Cidade store as reference not the id of the estado but its code. Performing tests, I stopped exactly where the field codigo_estado table Cidade is fed and the past value is exactly what is desired, but after the SaveChanges() when I look in the bank I see that there is another value.

You can help me find what I’m doing wrong?

Thank you very much!

1 answer

2


In this mapping:

 HasRequired(x => x.Estado)
            .WithMany(x => x.CidadeLista)
            .HasForeignKey(x => x.CodigoEstado);

Are you saying in which field of the table Cidade you will be recording the id of the Estado, 'cause it’s logical that if it’s a reference, it has to be the table ID estado.

If it is a field that is not FK then you can manually fill in.

Just a hint: leave the code below outside the loop:

context.Configuration.LazyLoadingEnabled = false;
context.Cidade.AddRange(novaListaCidade);
context.SaveChanges();

I would use the AddRange, or at least leave only the Add within the loop and the SaveChanges() outside the loop. This would increase performance and whether in any record of the Insert trouble would occur rollback at all automatically.

  • Hello Tania, With the exclusion of the relationship the insertion worked normally. Regarding the suggestions offered, you are right, it is better to put everything in a list and then access the bank only once. I am already changing the code. Anyway, can you tell if it is possible to use a field other than Id to use as FK? Thank you very much!

Browser other questions tagged

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