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

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

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

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

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

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

4b9b3361

Ответ 1

[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; 
        }
    }
}

Ответ 2

Я видел это раньше, вам может понадобиться преобразовать поле 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);
  }
}

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

Ответ 3

Ummm Интересно, может ли кто-нибудь угодить здравому смыслу проверить мое решение. Это очень похоже на принятый ниже ответ, но после прочтения блога Rick Strahl о 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();

Неужели я здесь глуп? Кажется, что это работает.