ADO.Net Entity Framework На объект сущности не могут ссылаться несколько экземпляров IEntityChangeTracker.

Я пытаюсь сохранить свой контакт, в котором есть ссылки на ContactRelation (только отношения контакта, женатый, одинокий и т. д.) и Country. Но каждый раз, когда я пытаюсь сохранить свой контакт, который проверяется, я получаю исключение «ADO.Net Entity Framework. На объект сущности не могут ссылаться несколько экземпляров IEntityChangeTracker».

public Contact CreateContact(Contact contact)
{
    _entities.AddToContact(contact); //throws the exception
    _entities.SaveChanges();
    return contact ;
}

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

Спасибо, Питер


person Peter    schedule 29.03.2009    source источник


Ответы (3)


[Обновление]
Поскольку используется L2E, вам необходимо сначала сохранить все связанные объекты, прежде чем вы сможете сохранить основной объект. Что имеет смысл, иначе вы бы создали (в моем примере) художника без его контактного объекта. Это запрещено структурой базы данных.
[/Update]

Вот моя реализация, которая сработала.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Artist artist, [Bind(Prefix = "Contact")] Contact contact, [Bind(Prefix = "Country")] Country country, [Bind(Prefix = "ContactRelationship")] ContactRelationship contactRelationship)
{
    ViewData["Countries"] = new SelectList(new CountryService(_msw).ListCountries().OrderBy(c => c.Name), "ID", "Name");
    ViewData["ContactRelationships"] = new SelectList(new ContactRelationshipService(_msw).ListContactRelationships().OrderBy(c => c.ID), "ID", "Description");

    country = _countryService.GetCountryById(country.ID);
    contact.Country = country;
    contactRelationship = _contactRelationshipService.GetContactRelationship(contactRelationship.ID);
    contact.ContactRelationship = contactRelationship;
    if(_contactService.CreateContact(contact)){
        artist.Contact = contact;
        if (_service.CreateArtist(artist))
            return RedirectToAction("Index");        
    }
    return View("Create");
}

А затем в моем ContactRepository:

public Contact CreateContact(Contact contact)
{
    _entities.AddToContact(contact); //no longer throws the exception
    _entities.SaveChanges();
    return contact ;
}

Я также обнаружил на этом веб-сайте, что лучше всего сохранять один и тот же контекст во всем приложении, поэтому теперь я использую для этого специальный класс данных:

Рик Страл и Сэмюэл Маечем научили меня, что вы должны сохранять свой контекст данных для каждого пользователя для каждого запроса. Это означает размещение его в HttpContext для веб-приложений. Прочтите все об этом здесь

public class Data
{
    public static MyDBEntities MyDBEntities
    {
        get
        {
            if (HttpContext.Current != null && HttpContext.Current["myDBEntities"] == null)
            {
                HttpContext.Current["myDBEntities"] = new MyDBEntities ();
            }
            return HttpContext.Current["myDBEntities"] as MyDBEntities;
        }
        set { 
            if(HttpContext.Current != null)
                HttpContext.Current["myDBEntities"] = value; 
        }
    }
}
person Peter    schedule 29.03.2009
comment
Спасибо, Питер, я трачу около часа, пытаясь найти такое же решение. Еще раз спасибо - person Geo; 13.09.2009

Я видел это раньше, возможно, вам придется преобразовать поле Reference в EntityKey перед сохранением, а затем загрузить его после сохранения. Вместо этого попробуйте этот код:

public Contact CreateContact(Contact contact){
    contact.ConvertContactRelationToReference();
    _entities.AddToContact(contact); 
    //throws the exception
    _entities.SaveChanges();
    contact.ContactRelation.Load();
    return contact;
}

public partial class Contact
{
  public void ConvertContactRelationToReference()
  {
    var crId = ContactRelation.Id;
    ContactRelation = null;
    ContactRelationReference.EntityKey = new EntityKey("MyEntities.ContactRelations", "Id", crId);
  }
}

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

person bendewey    schedule 29.03.2009
comment
спасибо, что указали мне правильное направление, вы не против, если я поставлю свой ответ в качестве принятого ответа? - person Peter; 01.04.2009
comment
Если я помог, вы можете бросить мне голос. Добро пожаловать, чтобы отметить себя как выбранный ответ, но вы не получите за это никакой репутации. - person bendewey; 02.04.2009
comment
Не могли бы вы объяснить, зачем все это нужно для, казалось бы, простой операции Save()? - person Ryan Shripat; 20.05.2009
comment
Поскольку используется L2E, вам необходимо сначала сохранить все связанные объекты, прежде чем вы сможете сохранить основной объект. Что имеет смысл, иначе вы бы создали (в моем примере) художника без его контактного объекта. Это не допускается конструкцией базы данных. - person Peter; 20.05.2009

Ммм, интересно, может ли кто-нибудь проверить мое решение на вменяемость. Это очень похоже на принятый ответ ниже, но после прочтения блога Рика Страла о DataContext Life Management Меня беспокоит, что это не потокобезопасное решение для веб-приложения.

Я также обошел случай, когда я получил это сообщение об ошибке, получив доступ к моему объектному контексту, используя шаблон singleton.

Я добавил следующее в класс MyObjectContext:

// singleton
private static MyObjectContext context;
public static MyObjectContext getInstance()
{
    if (context == null)
    {
        context = new MyObjectContext ();
    }
    return context;
} 

И в моем сопоставителе репозитория для каждого объекта вместо создания нового экземпляра MyObjectContext я использую

var db = MyObjectContext.getInstance();

Я тут тупой? Кажется, это работает.

person user427875    schedule 05.12.2010
comment
Вы не ошиблись, синглтон DataContext в моем ответе - плохой дизайн. Вы должны сделать синглтон DataContext, но для каждого пользователя по запросу. т. е. вы должны поместить его в HttpContext для веб-приложения. см. этот пост: samscode.com/index.php/2009/12/ - person Peter; 06.12.2010