简体   繁体   中英

Can I use a foreach loop on Seed method operations with Entity Framework 6 - Update-Database command

Mainly I'm trying to insert all cities data coming from an Xml using a foreach loop to iterate through each state. We have more than 5000 city records, and this was the only approach I could come up with.

  // Cities Seeding foreach (var uf in Enum.GetValues(typeof(Uf))) { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load("http://servicos.cptec.inpe.br/~rserv/estados/cidade-" + uf.ToString() + ".xml"); int cityId = Convert.ToInt32(xmlDoc.SelectSingleNode("/climas/clima/estados/estado/cidades/cidade").Attributes["id"].Value); string cityName = xmlDoc.SelectSingleNode("/climas/clima/estados/estado/cidades/cidade").Attributes["nome"].Value.ToString(); bool capital = Convert.ToBoolean(xmlDoc.SelectSingleNode("/climas/clima/estados/estado/cidades/cidade").Attributes["capital"].Value); int stateId = 1; //if (!capital) //{ context.Cities.AddOrUpdate( c => c.CityId, new City { CityId = cityId, CityName = cityName, StateId = stateId }); //} //else //{ //context.Capitals.AddOrUpdate( // cp => cp.CityId, // new Capital // { // CityId = cityId, // CityName = cityName, // StateId = stateId // }); //} stateId++; } 

I'm not sure if makes any difference in this case but, State Id is a foreign key from States Table.

This is my error message:

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Npgsql.NpgsqlException: ERROR: 23503: insert or update on table "City" violates foreign key constraint "FK_public.City_public.States_StateId"

An error occurred while updating the entries. See the inner exception for details.

Like @Sirwan said, the exception you are seeing is telling you that you are violating the foreign key constraint to the states table. Judging by the FK name, it looks like you are using a stateId value that doesn't exist in the States table

insert or update on table "City" violates foreign key constraint "FK_public.City_public.States_StateId

You also said:

State Id is a foreign key from States Table

So, I'm assuming that the States table is a pre-populated table with the state records already in it. In other words, the states are not being inserted based on the XML file. Is that the case?

Your code also makes two main assumptions:

  1. It assumes that the number of items in the Uf enum is less than or equal to the number of records in the States table.

  2. It assumes that the items in the Uf enum are sorted matching the records in the States table sorted by StatedId ascending.

If assumption 1 is invalid, ie you have more records in the Uf enum than you have in the States table, you will try to insert records using a stateId that doesn't exist.

if assumption 2 is invalid, ie the Uf enum elements are not sorted matching the stateId in the States table, you will insert the cities to the wrong state.

Based on the exception you posted, I bet that assumption 1 is invalid, that the number of records on the Uf enum doesn't match the number of records in the States table. Or, the other option is that the StateId values in the States table doesn't match the raw number of elements in the enum.

For example, I saw that you are from Brasil, where we have 27 states. Here we have three options for your error:

  1. States table doesn't have all the 27 states
  2. The StateId values in the States table don't start from 1
  3. The StateId values in the States table are not contiguous, ie they don't go from 1-27 but have gaps like : 1,2,3,6,7,8,9 ...

In all the scenarios above, your code would end up using an invalid stateId that will violate the FK constraint.

The less brittle way to write this code, while possibly paying a small performance tax, would be iterate over the values of the State table instead of using the Uf enum. That way, you can make sure that the StateId value that you are assigning to the record matches the one from the table:

foreach (var state in context.States)
{
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load("http://servicos.cptec.inpe.br/~rserv/estados/cidade-" + state.Name + ".xml");
    int cityId = Convert.ToInt32(xmlDoc.SelectSingleNode("/climas/clima/estados/estado/cidades/cidade").Attributes["id"].Value);
    string cityName = xmlDoc.SelectSingleNode("/climas/clima/estados/estado/cidades/cidade").Attributes["nome"].Value.ToString();

    context.Cities.AddOrUpdate(
        c => c.CityId,
        new City
        {
            CityId = cityId,
            CityName = cityName,
            StateId = state.StateId
        });
}

This error is telling you that you are violating the foreign key constraint. Check that there is not existing data in the database that is conflicting with the FK constraint causing the creation to fail.

One more thing : Why do you increment the stateId ? As you mentioned you have more than 5000 city records, So the State table must contains more than records too.

This is how my code looked in the end:

context.SaveChanges();

    //Cities Seeding
    int stateId = 1;
    foreach (var uf in Enum.GetValues(typeof(Uf)))
    {

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load("http://servicos.cptec.inpe.br/~rserv/estados/cidade-" + uf.ToString() + ".xml");
        XmlElement root = xmlDoc.DocumentElement;
        XmlNodeList nodes = root.SelectNodes("/climas/clima/estados/estado/cidades/cidade");
        foreach (XmlNode node in nodes)
        {
            int cityId = Convert.ToInt32(node.Attributes["id"].Value);
            string cityName = node.Attributes["nome"].Value.ToString();
            bool cityIsCapital = Convert.ToBoolean(node.Attributes["capital"].Value);
            context.Cities.AddOrUpdate(
            c => c.CityId,
            new City()
            {
                CityId = cityId,
                CityName = cityName,
                CityIsCapital = cityIsCapital,
                StateId = stateId
            });
        }
        stateId++;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM