Как сохранить дочерние отношения в 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 в своем ответе, размещение большего количества вашего кода поможет.