Подтвердить что ты не робот

Связь между двумя объектами не может быть определена, поскольку они привязаны к различным объектам ObjectContext

Я прочитал несколько вопросов/ответов, которые связаны с этим конкретным сообщением об ошибке, но я не совсем понимаю подходящее решение.

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

Я создал простое консольное приложение, которое легко вызывает ошибку. Схема очень проста, а затем код.

Как я могу получить два разных объекта для совместного использования одного и того же контекста? Должен ли я действительно создавать новый контекст, загружать два объекта снова (хотя у меня их уже есть), просто связать их и сохранить?

Если я просто пропустил уже существующий, подходящий вопрос/ответ, пожалуйста, укажите мне нужное место.

Simple EF4 Model diagram

internal class Program {

    private static void Main(string[] args) {
        DeleteAllEntities();
        CreateInitialEntities();
        Owner o = LoadOwner();
        Child c = LoadChild();
        AssociateAndSave(o, c);
    }

    private static void AssociateAndSave(Owner o, Child c) {
        using (var context = new ModelEntities()) {
            // Exception occurs on the following line.
            o.Children.Add(c);
            context.Attach(o);
            context.SaveChanges();
        }
    }

    private static Owner LoadOwner() {
        using (var context = new ModelEntities()) {
            return ((from o in context.Owners
                     select o).First());
        }
    }

    private static Child LoadChild() {
        using (var context = new ModelEntities()) {
            return ((from c in context.Children
                     select c).First());
        }
    }

    private static void CreateInitialEntities() {
        using (var context = new ModelEntities()) {
            Owner owner = new Owner();
            Child child = new Child();
            context.Owners.AddObject(owner);
            context.Children.AddObject(child);
            context.SaveChanges();
        }
    }

    private static void DeleteAllEntities() {
        using (var context = new ModelEntities()) {
            List<Child> children = (from c in context.Children
                                    select c).ToList();
            foreach (var c in children)
                context.Children.DeleteObject(c);
            List<Owner> owners = (from o in context.Owners
                                  select o).ToList();
            foreach (var o in owners)
                context.Owners.DeleteObject(o);
            context.SaveChanges();
        }
    }
}
4b9b3361

Ответ 1

Вы должны получить ссылку на объекты child и owner в том же контексте. Подходом для этого было бы получить идентификаторы, а затем передать их как параметры методу AssociateAndSave(int oId, int cId).

Затем вы извлекаете ссылки на объекты в том же контексте, и вы делаете вложение.

private static void Main(string[] args)
{
    DeleteAllEntities();
    CreateInitialEntities();
    int oId = LoadOwnerId();
    int cId = LoadChildId();
    AssociateAndSave(oId, cId);
}

private static int LoadOwnerId()
{
    using (var context = new ModelEntities())
    {
        return (from o in context.Owners
                select o).First().Id;
    }
}

private static int LoadChildId()
{
    using (var context = new ModelEntities())
    {
        return (from c in context.Children
                select c).First().Id;
    }
}

private static void AssociateAndSave(int oId, int cId)
{
    using (var context = new ModelEntities())
    {
        var owner = (from o in context.Owners
                        select o).FirstOrDefault(o => o.ID == oId);
        var child = (from o in context.Children
                        select o).FirstOrDefault(c => c.ID == cId);

        owner.Children.Add(child);
        context.Attach(owner);
        context.SaveChanges();
    }
}

Ответ 2

Вы не можете удалять объекты из одного контекста с экземпляром другого контекста, поскольку каждый контекст отслеживает его объекты отдельно.

Один идеал должен предоставить каждому из ваших методов параметр вашего типа контекста, чтобы ваши операции выполнялись в одном контексте.

Пример:

private static void CrudOperationExample(DBContext contextInstane)
{
    //perform crud operations.
}

Я хочу сделать это более красиво, я предлагаю вам искать инъекцию зависимостей, так как это очень полезно в ORM.