【问题标题】:Entity Framework - Saving child entities实体框架 - 保存子实体
【发布时间】:2013-12-15 16:04:01
【问题描述】:

我正在使用 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 的新手,我一直在努力保存/更新任何具有子集合的实体。当事物与上下文相关联时,我似乎无法思考。

【问题讨论】:

  • 您正在附加已跟踪的实体。只需获取父级并使用 parent.Childern.Add() 或 parent.ChildernId = id 添加子实体。我希望你没有在这里使用延迟加载。
  • 使用Any() 比使用Count() > 0 更好。 Count() 循环遍历整个集合,Any() 没有谓词只是偷看第一个项目并返回。
  • 谢谢。我已经更新了我的代码以使用 Any()。我仍然被困住了。如果我从我自己的数据源中提取子属性,这不会是一个大问题,但因为我基本上每次都发送一个“新”项目(即它还没有来自我的数据库的 ID) .对不起,如果这很愚蠢。我真的很难掌握 EF。
  • 你的 country_code 在数据库中是否有唯一的约束?如果没有,我会尝试添加一个并再次使用附加。
  • 为什么实体框架将现有对象重新插入到我的数据库中? msdn.microsoft.com/en-us/magazine/dn166926.aspx

标签: c# entity-framework


【解决方案1】:

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

这可能不是最好的方法,但这是我能想到的第一个方法。

【讨论】:

  • 您好,感谢您的回复。我早些时候尝试过。在这种情况下它不能分配给国家,因为它是一个 foreach 迭代变量。
  • 成功了!非常感谢。正如你所说,可能不是最好的方法,但它有效,我的时间不多了。再次感谢 =)
【解决方案2】:

假设 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 分配现有Country 的值。在我的小宇宙中,我会使用 T4 模板为此代码生成解决方案...

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    相关资源
    最近更新 更多