Как сохранить дочерние отношения в Entity Framework
У меня есть проект Entity Framework v1. У меня есть два объекта (Роли и Разрешения), которые имеют отношения "многие ко многим" друг с другом. Я передаю объект для сохранения (через вызов WCF, я сам не создаю его из контекста), который имеет новые записи в отношениях "многие ко многим".
Я использую "context.ApplyPropertyChanges", чтобы обновить запись новыми свойствами. Я знаю, что это не обновляет отношения. Я пытаюсь либо выполнить ChildCollection.Add(relatedObject); или ChildCollection.Attach( relatedObject).
Когда я использую метод "Добавить", я получаю сообщение об ошибке: Объект нельзя добавить в ObjectStateManager, поскольку он уже имеет EntityKey. Используйте ObjectContext.Attach для присоединения объекта, имеющего существующий ключ.
Когда я использую метод "Прикрепить", я получаю сообщение об ошибке: Объект нельзя добавить в ObjectStateManager, поскольку он уже имеет EntityKey. Используйте ObjectContext.Attach для присоединения объекта, имеющего существующий ключ.
Я очень расстраиваюсь, и я думаю, что могу слышать, как Entity Framework смеется над мной.
Кто-нибудь знает, как я могу это решить?
MyRole x = context.Roles.FirstOrDefault(a => a.RoleId == this.RoleId);
context.ApplyPropertyChanges("Roles", this);
foreach (MyPermission p in this.Permissions)
{
x.Permissions.Add(p);
// ^ or v
x.Permissions.Attach(p);
}
context.SaveChanges();
Спасибо.
Ответы
Ответ 1
Ого. После 20 или около того прямых часов по этой проблеме я начинаю ненавидеть Entity Framework. Вот код, который сейчас работает. Я был бы признателен за любые советы о том, как сделать это более упорядоченным.
Я переработал службу WCF, так что есть только один контекст данных. Спасибо Крейгу.
Затем мне пришлось изменить код на следующее:
MyRole x = context.Roles.FirstOrDefault(a => a.RoleId == this.RoleId);
if (x == null) // inserting
{
MyApplication t = this.Application;
this.Application = null;
context.Attach(t);
this.Application = t;
}
else // updating
{
context.ApplyPropertyChanges("Roles", this);
x.Permissions.Load();
IEnumerable<Guid> oldPerms = x.Permissions.Select(y => y.PermissionId);
List<MyPermission> newPerms = this.Permissions.Where(y => !oldPerms.Contains(y.PermissionId)).ToList();
IEnumerable<Guid> curPerms = this.Permissions.Select(y => y.PermissionId);
List<MyPermission> deletedPerms = x.Permissions.Where(y => !curPerms.Contains(y.PermissionId)).ToList();
// new
foreach (MyPermission p in newPerms)
{
x.Permissions.Add(context.Permissions.First(z => z.PermissionId == p.PermissionId));
}
// deleted
foreach (MyPermission p in deletedPerms)
{
x.Permissions.Remove(context.Permissions.First(z => z.PermissionId == p.PermissionId));
}
}
Ответ 2
Вы используете одновременно несколько объектов ObjectContext (переменная context
и whereever this
). Не делай этого. Это только сделает вещи очень трудными для вас. Используйте один объект ObjectContext за раз.
Я могу дать более конкретный совет, если вы покажете больше кода.
Ответ 3
Я подозреваю, что вы получаете ошибки, потому что ObjectContext думает, что вы пытаетесь добавить новый объект, но обнаруживает, что у него уже есть EntityKey. Я использую метод AttachTo объекта ObjectContext для присоединения уже существующих объектов к их EntitySet. У меня были результаты, генерирующие мои объекты из заглушек или попадающих в базу данных. Таким образом, когда вы добавляете объект в свойство навигации на свой объект, ObjectContext находит в нем сущность EntitySet и знает, что это уже существующий объект, а не новый. Я не знаю, ясно ли это. Я мог бы опубликовать код, если это поможет. Как сказал г-н Stuntz в своем ответе, размещение большего количества вашего кода поможет.