实体框架 - 保存子实体
问题描述:
我使用EF和WebAPI并试图保存具有许多子属性(例如城市,国家等)的新对象。这些属性的数据是从外部源获取的,但我想将它们与我的对象一起保存到数据库中以用于报告目的。出于这个原因,我需要首先检查是否新父项与新父项一起存在(请记住,它不会从我的数据库中提取)。实体框架 - 保存子实体
如果我选择了一个我已经保存的城市,它会保存一个重复的行,因为传入的对象没有我的城市ID,所以EF认为这是一个新项目。
我已经试过如果它已经在数据库中,但它不会让我附上。它表示该项目已被上下文跟踪。
这是我的代码,用于在保存新父项之前检查并保存其中一个子集合。
foreach (HBCountry country in hbcampaign.HBTargetingSpec.HBCountries)
{
if (db.HBCountries.Any(c => c.country_code == country.country_code))
{
country.CountryID = db.HBCountries.Where(c => c.country_code == country.country_code)
.FirstOrDefault()
.CountryID;
db.HBCountries.Attach(country);
}
else
{
db.HBCountries.Add(country);
}
}
我需要抓住从我的背景下,现有实体的ID,但在那之后我不能附上,让EF知道,它并不需要为这个项目的新条目。
我对EF很新,我一直在努力保存/更新任何具有子集合的实体。我似乎无法将我的想法包括在附加到上下文时以及什么时候没有。
答
不要尝试设置Id,只需使用现有的国家实体创建新列表(并尽可能少地查询尽可能):
var newList = new List<HBCountry>();
foreach (HBCountry country in hbcampaign.HBTargetingSpec.HBCountries)
{
var countryMatch = db.HBCountries.FirstOrDefault(c => c.country_code == country.country_code)
if (countryMatch != null)
{
newList.Add(countryMatch);
}
else
{
newList.Add(country);
}
}
hbcampaign.HBTargetingSpec.HBCountries = newList;
这可能不是最好的方式来做到这一点,但它是我能想到的第一个。
答
假设country_code列上的唯一约束不能解决附加实体的问题。我想试试这个...
var countryCodes = hbcampaign.HBTargetingSpec.HBCountries.Select(c => country.country_code);
// Gives you the list of existing countries in one SQL query
var existingCountries = db.HBCountries.Where(c =>
countryCodes.Contains(c.country_code);
foreach (HBCountry country in existingCountries)
{
var existingCountry = hbcampaign.HBTargetingSpec.HBCountries.FirstOrDefault(c => c.country_code == country.country_code);
existingCountry.CountryID = country.CountryID;
db.HBCountries.Detach(country);
db.HBCountries.Attach(existingCountry);
}
var newCountries = hbcampaign.HBTargetingSpec.HBCountries.Where(c => !existingCountries.Any(c2 => c2.country_code == c.country_code);
foreach (HBCountry country in newCountries)
db.HBCountries.Add(country);
或者更简单一些,只需在Country中指定existingCountry上的值即可。在我的小宇宙我的代码生成此使用T4模板的解决方案......
你已经安装跟踪实体。只需获取父项并使用parent.Childern.Add()或parent.ChildernId = id添加子实体。我希望你不要在这里使用Lazy Loading。 –
最好使用'Any()'而不是'Count()> 0'。 'Count()'遍历整个集合,没有谓词的Any()'只是查看第一个项目并返回。 –
谢谢。我更新了我的代码以使用Any()。我仍然坚持。如果我从我自己的数据源中提取子属性,这不会是一个大问题,但是因为我基本上每次都发送一个“新”项目(即,它没有来自我的数据库的ID) 。对不起,如果这非常愚蠢。我真的很难与EF握手。 – GooseZA