我可以在实体框架6-更新数据库命令的种子方法操作上使用foreach循环吗
本文关键字:操作上 子方法 foreach 循环 种子 框架 实体 更新 命令 数据库 我可以 | 更新日期: 2023-09-27 18:09:54
我主要尝试使用foreach循环来遍历每个状态,插入来自Xml的所有城市数据。我们有5000多个城市记录,这是我唯一能想到的方法。
// 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++; }
我不确定在这种情况下是否有什么不同,但是,State Id是States表中的外键。
这是我的错误信息:
System.Data.Entity.Infrastructure.DbUpdateException:更新条目时出错。有关详细信息,请参阅内部异常。--->System.Data.Entity.Core.UpdateException:更新条目时出错。有关详细信息,请参阅内部异常。--->Npgsql.NpgsqlException:错误:23503:在表"City"上插入或更新违反了外键约束"FK_public.City_public.States_StateId">
更新条目时出错。有关详细信息,请参阅内部异常。
正如@Sirwan所说,您看到的异常告诉您,您违反了states表的外键约束。根据FK名称判断,您似乎使用了States
表中不存在的stateId
值
在表"City"上插入或更新违反外键约束"FK_public.City_public.States_StateId
你还说:
State Id是States表中的外键
因此,我假设States表是一个预先填充的表,其中已经有状态记录。换句话说,状态不是基于XML文件插入的。是这样吗?
您的代码还做出了两个主要假设:
-
它假设
Uf
枚举中的项目数小于或等于States
表中的记录数。 -
它假设
Uf
枚举中的项目与States
表中按StatedId
升序排序的记录相匹配。
如果假设1无效,即Uf
枚举中的记录比States
表中的记录多,则将尝试使用不存在的stateId插入记录。
如果假设2无效,即Uf
枚举元素的排序与States
表中的stateId
不匹配,则将城市插入错误的状态。
根据您发布的异常,我敢打赌假设1是无效的,即Uf
枚举上的记录数与States
表中的记录数不匹配。或者,另一种选择是States
表中的StateId
值与枚举中的原始元素数不匹配。
例如,我看到你来自巴西,那里有27个州。对于您的错误,我们有三个选项:
States
表没有包含所有27个状态States
表中的StateId
值不是从1开始的States
表中的StateId
值不是连续的,即它们不是从1-27开始的,而是有间隙,如:1,2,3,6,7,8,9 ...
在上面的所有场景中,您的代码最终将使用一个无效的stateId
,这将违反FK约束。
编写此代码的不那么脆弱的方法是迭代State
表的值,而不是使用Uf
枚举,同时可能需要支付少量的性能税。这样,您可以确保分配给记录的StateId
值与表中的值匹配:
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
});
}
此错误表明您违反了外键约束。请检查数据库中是否存在与FK约束冲突的现有数据,从而导致创建失败。
还有一件事:为什么要增加stateId
?正如您所提到的,您有5000多个城市记录,因此State表也必须包含多个记录。
这就是我的代码最终的样子:
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++;
}