Эта ошибка обычно возникает, когда вы создаете новую запись в MetaTable с отношением внешнего ключа, и запись внешнего ключа уже существует.
Например, допустим, у вас есть таблица контактов и таблица адресов, и каждый контакт может содержать несколько адресов. Ошибка возникает при создании новой записи контакта и попытке вручную связать существующую запись адреса с этим новым контактом.
Предполагая, что переданный идентификатор адреса представляет существующую запись адреса, это не работает:
public class Contact
{
public int Contact_ID { get; set; }
public string Name { get; set; }
public Address ContactAddress { get; set; }
public string Phone { get; set; }
}
public class Address
{
public int Address_ID { get; set; }
public string Street { get; set; }
public string CityState { get; set; }
public string ZIP { get; set; }
}
public void CreateNewContact(int addressID)
{
Contact contact = new Contact();
contact.Name = "Joe Blough";
contact.ContactAddress.Address_ID = addressID;
contact.Phone = "(555) 123-4567";
DataContact.SubmitChanges();
}
Исторически сложилось так, что разработчики SQL обучаются просто передавать значение идентификатора, чтобы произошло волшебство. В LINQ-to-SQL, поскольку активность базы данных абстрагирована, мы должны передать весь объект, чтобы механизм LINQ мог правильно отражать необходимые изменения в ChangeSet. В приведенном выше примере механизм LINQ предполагает, что вы запрашиваете создание новой записи адреса, потому что у него не было с ней работать, когда был выполнен SubmitChanges, и он должен соблюдать договор, установленный связью внешнего ключа. Создается пустая запись адреса с переданным значением идентификатора. Ошибка возникает из-за того, что это значение идентификатора уже существует в таблице данных, а набор изменений не пометил дельту адреса как обновление.
Исправление - передать всю запись, а не только значение идентификатора:
contact.ContactAddress = DataContext.Addresses.Where(a => a.Address_ID == addressID).Single();
Теперь механизм LINQ может правильно пометить входящую запись адреса как существующую и не пытаться воссоздать ее.