2016-03-20 7 views
0

У меня есть проект, который широко использует Entity Framework. И все работает отлично.Entity Framework не обновляет существующий связанный объект

Однако есть одно обновление, которое я пытаюсь сделать, и оно не обновляется, и не возникает ошибка.

Основным процессом является то, что я беру существующий объект, работаю с ним, чтобы создать новый (и другой тип) объекта. Новый объект сохраняет просто отлично, но существующего нет.

Обычно, когда я сталкивался с этим, это означает, что объект не привязан к контексту. Тем не менее, это так, и я попытался присоединить его снова, а также «Добавить», но мне не повезло.

 if (fileRowEntity != null) 
     { 
      this.Context.FileRowEntities.Attach(fileRowEntity); 
      fileRowEntity.FileRowStatusId = (int)FileRowStatus.Converted; 
      fileRowEntity.EdiDocument = ediDocument; 
     } 

     ediDocument.InsertedDate = DateTime.Now; 
     ediDocument.EdiDocumentGuid = Guid.NewGuid(); 
     ediDocument.DocumentMetatdata = null; 
     this.Context.EdiDocuments.Add(ediDocument); 
     var count = this.Context.SaveChanges(); 

The ediDocument сохраняется, но fileRowEntity не сохраняется.

Я разрываю волосы, пытаясь понять это. Я попробовал второй явно сэкономить на fileRowEntity, но он возвращается с нулевыми изменениями спасенных:

 if (fileRowEntity != null) 
     { 
      fileRowEntity.EdiDocumentId = ediDocument.EdiDocumentId; 
      fileRowEntity.Column100 = "X"; 
      this.Context.FileRowEntities.Attach(fileRowEntity); 
      count = this.Context.SaveChanges(); 
     } 

count всегда равна нулю, а база данных не обновляется.

Я не знаю, что еще попробовать отладить.

+0

Прикрепление объекта не помечено как измененное ... вы пробовали 'Context.Entry (fileRowEntity) .State = EntityState.Modified;'? (нет необходимости прикреплять его, это будет прикреплять объект, если он также отсоединен). Если объект не является прокси-сервером и/или он был загружен заранее, EF не будет знать, что в него были внесены изменения, если вы не сообщите об этом, поэтому он не будет делать никаких обновлений. Явное указание на это как «Модифицированное» должно работать. – Jcl

+0

Спасибо. Да, это действительно делает работу сохранения. Означает ли это, что сущность фактически не в том же контексте? Насколько я могу судить, один и тот же менеджер сущностей используется для извлечения сущностей в качестве их сохранения. –

+0

Когда объект загружается из базы данных, его исходные значения (по мере их восстановления) сохраняются в контексте (вы можете проверить их в 'Context.Entry (entity) .OriginalValues') ... когда dbcontext проверяет его (вызывая 'DetectChanges'), он сохраняет новые значения (вы можете проверить их в' Context.Entry (entity) .CurrentValues'), и если какой-либо из них будет изменен, тогда при обновлении изменений генерируется 'UPDATE' , Поэтому, если исходный объект был извлечен из базы данных по тому же самому контексту, то да, он должен обнаружить изменения и сохранить изменения. – Jcl

ответ

2

Прикрепление объекта к контексту не помечает его как измененное.

В вашем случае предполагается, что экземпляр контекста, в котором вы вызываете SaveChanges(), не совпадает с тем, что извлечен объект fileRowEntity, поэтому он не знает, что он был изменен (или изменен).

Когда DbContext извлекает объект из хранилища, он хранит копию своих исходных значений (если не используется AsNoTracking() по этому запросу), и всякий раз, когда он обнаруживает изменения при вызове DetectChanges(), которое вы можете сделать в явном виде, но обычная реализация DbContext вызовет ее сама по себе во многих точках), она сохранит новые значения объекта. Если есть различия между ними, следующий вызов SaveChanges будет обновлять объект в хранилище/базе данных.

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

Использования Context.Entry(fileRowEntity).State = EntityState.Modified; должен сказать EF, что ваше лицо было изменен, и он будет генерировать команду обновления при вызове SaveChanges() для всей сущности (он отправит все значения полей в UPDATE SQL). Обратите внимание, что это также придает сущности, если она не привязана к контексту (нет необходимости присоединять его, а затем устанавливать его состояние).

Вы также можете отметить только те свойства, которые были изменены (или изменить объект OriginalValues), таким образом ваш запрос будет оптимизирован (он обновит только те поля, которые действительно изменились).Немного громоздко отслеживать эти изменения самостоятельно, но если вам нужна эта дополнительная оптимизация, это стоит сделать (лично, если не будет критической нагрузки на сервер базы данных, и каждый бит подсчитывается, я бы этого не сделал, но ваш выбор)

1

Существует вторая причина описанного выше поведения: Этот код будет отключить отслеживание изменений:

Context.Configuration.AutoDetectChangesEnabled = false; 

После того как я нашел, что это было установлено в конструкторе и удалить его, все работало, как ожидалось.

+1

Правильно. Значение по умолчанию - автоматическое, и я не думал о возможности того, что вы могли бы отключить его. Если вы заметили медленное поведение после включения автоматического обнаружения изменений, вы можете явно вызвать DetectChanges. EF имеет тенденцию делать больше детектирования, чем необходимо :-) – Jcl

+0

Хорошая точка. Опять же, спасибо, я не мог понять этого: –