2013-12-15 18 views
0

Я использую EF и WebAPI и пытаюсь сохранить новый объект с множеством дочерних свойств (например, город, страна и т. Д.). Данные для этих свойств извлекаются из внешнего источника, но я хочу сохранить их в своей базе данных вместе с моим объектом для целей отчетности. По этой причине мне нужно сначала проверить, существует ли новый дочерний элемент вместе с новым родителем (помните, что он не извлекается из моей базы данных).Entity Framework - Сохранение дочерних объектов

Если я выбрал, например, город, который я уже сохранил, он сохраняет повторяющуюся строку, потому что объект, который прошел, не имеет идентификатора моего города, поэтому 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); 
    }     
} 

мне нужно, чтобы захватить идентификатор существующего объекта из моего контекста, но после этого я не могу приложить, и пусть EF знать, что это не нужно, чтобы создать новую запись для этого элемента.

Я довольно новичок в EF, и я постоянно борюсь с сохранением/обновлением любых объектов, у которых есть дочерние коллекции. Кажется, я не могу обдумать, когда что-то связано с контекстом, а когда нет и т. Д.

+0

Вы прикрепление уже отслеживаются сущность. Просто получите родительский элемент и либо используйте parent.Childern.Add(), либо parent.ChildernId = id, чтобы добавить дочерний объект. Надеюсь, вы не используете Lazy Loading здесь. –

+0

Лучше использовать 'Any()', чем 'Count()> 0'. 'Count()' цикл через всю коллекцию, 'Any()' без предиката просто заглядывает в первый элемент и возвращается. –

+0

Спасибо. Я обновил свой код, чтобы использовать Any(). Я все еще застрял. Если бы я вытаскивал дочерние свойства из моего собственного источника данных, это не было бы большой проблемой, а потому, что я в основном отправляю «новый» элемент каждый раз (т. Е. Он еще не имеет идентификатора из моего БД) , Извините, если это очень глупо. Я действительно изо всех сил пытаюсь справиться с EF. – GooseZA

ответ

0

Не пытайтесь установить идентификатор, просто создайте новый список с существующими сущностями страны (и сделайте как можно меньше запросы как можно):

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

0

Предполагая, что уникальное ограничение на столбец 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); 

Или даже проще, просто присвойте значения на existingCountry из страны. В моей маленькой вселенной я бы закодировать генерировать решение для этого с помощью шаблонов T4 ...

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

Смежные вопросы