2012-04-23 8 views
3

я после многих-To-Many отношения между двумя субъектами RelayConfig и StandardContactEntity Framework Обновление Многие-ко-многим - ПОКО

Entities:

public class RelayConfig : EntityBase, IDataErrorInfo { 
    ... 
    //Associations 
    public virtual ICollection<StandardContact> StandardContacts { get; set; } 
} 


public class StandardContact :EntityBase, IDataErrorInfo { 
    ... 
    //Associations 
    public virtual ICollection<RelayConfig> RelayConfigs { get; set; } 
} 

Теперь я Я пытаюсь обновить RelayConfig и его отношения с StandardContact. Вот код, который обновляет RelayConfig.

public class RelayConfigRepository : GenericRepository<RelayConfig> { 
    .... 

    public void Update(RelayConfig relayConfig, List<StandardContact> addedContacts, List<StandardContact> deletedContacts) { 
     context.RelayConfigs.Add(relayConfig); 
     if (relayConfig.Id > 0) { 
      context.Entry(relayConfig).State = EntityState.Modified; 
     } 

     addedContacts.ForEach(ad => relayConfig.StandardContacts.Add(ad)); 

     foreach (StandardContact standardContact in relayConfig.StandardContacts) { 
      if (standardContact.Id > 0) { 
       context.Entry(standardContact).State = EntityState.Modified; 
      } 
     } 

     relayConfig.StandardContacts.ToList().ForEach(s => { 
      if (deletedContacts.Any(ds => ds.Id == s.Id)) { 
       context.Entry(s).State = EntityState.Deleted; 
      } 
     }); 
    } 
    ... 
} 

Когда я запускаю обновление, я получаю исключение, внутреннее исключение которого приводится ниже.

InnerException: System.Data.SqlClient.SqlException 
     Message=Violation of PRIMARY KEY constraint 'PK__Standard__EE33D91D1A14E395'. Cannot insert duplicate key in object 'dbo.StandardContactRelayConfigs'. 

dbo.StandardContactRelayConfigs является таблица связывания, которая связывает RelayConfig и StandardContact. Как вы можете видеть, код обновления изменяет все сущности на измененное состояние, если Id> 0 (кроме удаленных записей, которые установлены в конце метода Update).

Я действительно не могу понять, почему инфраструктура сущности пытается вставить строку в связанную таблицу и не удается выполнить вышеуказанное исключение. Я уже изменяю EntityState существующих объектов RelayConfig.StandardContacts для Modified.

Короче, почему я получаю исключение, вставленное выше.

приветствия, Nirvan.

Edit: Параметры, чтобы обновить метод выше (addedContacts и deletedContacts) уже существующие объекты с Id> 0.

edit2: В соответствии с вашими предложениями я удалил код для вставки свежий (не существует в базе данных) записей из метода обновления. Поэтому теперь мой метод обновления добавляет существующие записи StandardContact к коллекции RelayConfig. Но я все еще не могу заставить код работать правильно. Сначала вот код, который я использую

public void Update(RelayConfig relayConfig, List<StandardContact> addedContacts, List<StandardContact> deletedContacts) { 
     context.RelayConfigs.Add(relayConfig); 

     if (relayConfig.Id > 0) { 
      context.Entry(relayConfig).State = EntityState.Modified; 
     } 


     addedContacts.ForEach(contact => { 
      context.StandardContacts.Attach(contact); 
      relayConfig.StandardContacts.Add(contact); 
      objectContext.ObjectStateManager. 
       ChangeRelationshipState(relayConfig, contact, rs => rs.StandardContacts, EntityState.Added); 
     }); 
    } 

На данный момент я просто концентрируюсь на добавленных рекордах. Вышеприведенный код работает хорошо, когда StandardContact (контактная переменная) не имеет никаких связей с другими существующими объектами RelayConfig. В этом случае в таблице соединений создается новая запись для каждого контакта, добавленного в коллекцию RelayConfig.StandardContacts. Но все становится уродливым (непредсказуемое поведение), когда StandardContact (контактная переменная) уже находится в отношениях с другими объектами RelayConfig. В этом случае, когда StandardContact добавляется в RelayConfig.StandardContacts Collection, StandardContact также добавляется в базу данных, тем самым создавая дубликат записи. Кроме того, также создается новый объект RelayConfig (я не знаю откуда) и вставлен в таблицу RelayConfigs. Я действительно не могу понять, как структура сущности работает с отношениями «многие-ко-многим».

@Ladislav, если у вас есть пример кода, который работает с обновлениями отношений «Множество ко многим» (для отдельных объектов), я могу попросить вас, пожалуйста, показать мне то же самое.

С уважением, Nirvan

Edit3 (раствор):

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

public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) { 

     context.Entry(relayConfig).State = EntityState.Modified; 

     relayConfig.StandardContacts.Clear(); 
     exposedContacts.ForEach(exposedContact => { 
      StandardContact exposedContactEntity = null; 
      exposedContactEntity = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id); 
      if (exposedContactEntity != null) { 
       relayConfig.StandardContacts.Add(exposedContactEntity); 
      } 
     }); 
    } 

С уважением, Nirvan.

ответ

10

Проблема в том, что отношение «многие ко многим» имеет свое собственное состояние. Так что, если вы звоните в этом:

addedContacts.ForEach(ad => relayConfig.StandardContacts.Add(ad)); 

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

foreach (StandardContact standardContact in relayConfig.StandardContacts) { 
    if (standardContact.Id > 0) { 
     context.Entry(standardContact).State = EntityState.Modified; 
    } 
} 

изменит состояние контактного объекта, но не состояние отношения - он по-прежнему отслеживается как новый (кстати, он не может быть изменен, а только добавлен, удален или не изменен). Поэтому, когда вы сохраняете изменения, отношения для всех ваших контактов добавляются в таблицу соединений, и если одно и то же отношение уже существует в базе данных, вы получите исключение (потому что таблица соединений содержит только два FK, которые также являются PK, и в таком случае одно и то же отношение = нарушение PK).

Кроме того, необходимо установить состояние для отношений с помощью:

var objectContext = ((IObjectContextAdapter)context).ObjectContext; 
objectContext.ObjectStateManager.ChangeRelatioshipState(...); 

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

+0

Благодарим за отзыв. Но у меня все еще есть сомнения. Предположим, что нет добавленных рекордов или удаленных рекордов. Предполагая, что RelayConfig имеет 2 записи StandardContact, и я хочу сохранить изменения в этих двух файлах StandardContact, нужно ли мне изменить состояние отношения этих двух стандартныхконтактов в дополнение к изменению их EntityState для изменения? Я имею в виду, как мы обновляем многие стороны отношений (пренебрегая добавленными и удаленными записями на данный момент). – Jatin

+0

Если вы добавите realayConfig, вы должны изменить состояния отношений на неизмененные. Если вы просто Attache realayConfig, вам не нужно ничего делать с этими отношениями, но добавление может вызвать другие проблемы, если вы хотите добавить новые отношения. –

+0

См. Мое редактирование с пометкой «Edit2»: – Jatin

Смежные вопросы