实体框架 - 保存子实体

问题描述:

我使用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很新,我一直在努力保存/更新任何具有子集合的实体。我似乎无法将我的想法包括在附加到上下文时以及什么时候没有。

+0

你已经安装跟踪实体。只需获取父项并使用parent.Childern.Add()或parent.ChildernId = id添加子实体。我希望你不要在这里使用Lazy Loading。 –

+0

最好使用'Any()'而不是'Count()> 0'。 'Count()'遍历整个集合,没有谓词的Any()'只是查看第一个项目并返回。 –

+0

谢谢。我更新了我的代码以使用Any()。我仍然坚持。如果我从我自己的数据源中提取子属性,这不会是一个大问题,但是因为我基本上每次都发送一个“新”项目(即,它没有来自我的数据库的ID) 。对不起,如果这非常愚蠢。我真的很难与EF握手。 – GooseZA

不要尝试设置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; 

这可能不是最好的方式来做到这一点,但它是我能想到的第一个。

+0

嗨,感谢您的回复。我早些时候尝试过。在这种情况下,它不能分配给国家,因为它是一个foreach迭代变量。 – GooseZA

+0

啊,当然。我的错。编辑答案。 –

+0

这个伎俩!非常感谢。正如你所说,可能不是最好的办法,但它的工作原理,我没有时间。再次感谢=) – GooseZA

假设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模板的解决方案......

http://msdn.microsoft.com/en-us/data/gg558520.aspx