ADO.Net Entity Framework На объектный объект нельзя ссылаться несколькими экземплярами IEntityChangeTracker - PullRequest
19 голосов
/ 29 марта 2009

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

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

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

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

Ответы [ 3 ]

21 голосов
/ 29 марта 2009

[Update]
Поскольку используется 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 ;
}

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

Рик Страл и Сэмюэль Маечам научили меня, что вы должны хранить свой текстовый текст для каждого пользователя по запросу. Это означает, что нужно поместить его в 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; 
        }
    }
}
5 голосов
/ 29 марта 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);
  }
}

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

2 голосов
/ 05 декабря 2010

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

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

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

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

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

var db = MyObjectContext.getInstance();

Я что, глупый здесь? Вроде работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...