2013-06-24 3 views
2

Редактировать

Я записал скринкаст с моей проблемой, вы можете найти его here, пожалуйста, смотрите, если у вас есть время.Entity Framework создает дубликаты сущностям

У меня есть следующий код, который должен выполнять функциональность AddOrUpdate, но вместо этого все существующие записи воссозданы, поэтому у меня есть несколько Нью-Йорков, несколько США. Я передаю EntityState с клиента, так что, если данные были изменены на клиенте, клиент соответствующим образом обновляет свойство EntityState и отправляет его на сервер.

[HttpPost, HttpGet, HttpPut] 
    public HttpResponseMessage SaveRecord(RecordViewModel record) 
    { 
     var model = Mapper.Map<Record>(record); 

     if (!ModelState.IsValid) 
     { 
      return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); 
     } 

     db.Attach(model); 

     try 
     { 
      db.SaveChanges(); 
     } 
     catch (DbUpdateConcurrencyException ex) 
     { 
      return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex); 
     } 

     return Request.CreateResponse(HttpStatusCode.OK, Mapper.Map<RecordViewModel>(model)); 
    } 

Я прилагаю объекты с помощью следующей функции

public void AttachAndMarkAs<T>(T entity, EntityState state, Func<T, object> id) where T : class 
    { 
     var entry = Entry(entity); 

     if (entry.State == EntityState.Detached) 
     { 
      var set = Set<T>(); 

      T attachedEntity = set.Find(id(entity)); 

      if (attachedEntity != null) 
      { 
       var attachedEntry = Entry(attachedEntity); 

       if (state != EntityState.Unchanged) 
       { 
        attachedEntry.CurrentValues.SetValues(entity); 
        attachedEntry.State = state; 
       } 
      } 
      else 
      { 
       entry.State = state; 
      } 
     } 
    } 

Который ретранслируется через следующие из них:

public void Attach(City entity) 
    { 
     if (entity != null) 
     { 
      Attach(entity.Country); 

      AttachAndMarkAs(entity, entity.EntityState ?? EntityState.Added, instance => instance.Id); 
     } 
    } 

    public void Attach(Country entity) 
    { 
     if (entity != null) 
     { 
      AttachAndMarkAs(entity, entity.EntityState ?? EntityState.Added, instance => instance.Id); 
     } 
    } 

Я не понимаю, какая часть кода ручки Добавление сущности вместо их обновления, поскольку значения EntityState верны ...

+1

Если вы говорите: «Я не понимаю, какая часть делает ...» делает что означает, что вы скопировали код из другого места? –

+0

Ваш EntityState имеет значение null, поэтому его всегда рассматривают как Add. – Maess

+0

Вы установили некоторые точки останова и посмотрели, что происходит? – MaxSC

ответ

3

Если yo u использует простой int для вашего идентификатора, вы можете использовать следующий метод.

public abstract class BaseEntity 
{ 
    public int Id { get; set; } 
} 

public void AddOrUpdate<T> (T entity) where T : BaseEntity 
{ 
    if(entity.Id > 0){ 
     Entry(entity).State = EntityState.Modified; 
    } 
    else 
    { 
     Set<T>().Add(entity); 
    } 
} 

// 

var model = Mapper.Map<Record>(record); 
db.AddOrUpdate(model); 
db.SaveChanges(); 
+0

Хм, позвольте мне попробовать ... – Lu4

+0

Действительно странно, проблема сохраняется ... – Lu4

+0

Я думаю, что у меня это есть, у меня есть внешняя Сущность, которая содержит дочерние. Ребенок - это свойства «Отдельно», которые создаются. – Lu4

2

Следует обратить внимание на то, как Entity Framework имеет дело с дочерними/ссылочными объектами при изменении состояния родительского объекта программным путем.

Посмотрите на этот article, который суммирует, как все работает во многих разных случаях.

В приведенном ниже примере, вы могли бы подумать, что все упомянутые объекты будут автоматически установлены в Modifiied:

using (var context = new BloggingContext()) 
{ 
    context.Entry(existingBlog).State = EntityState.Modified; 
    // Do some more work... 
    context.SaveChanges(); 
} 

Но на самом деле, они не будут. Как написано на статью:

Если у вас есть несколько объектов, которые должны быть помечены Модифицированный вы должны установить состояние для каждого из этих лиц в отдельности.

Наконец, вот так, как вам нужно обрабатывать AddOrUpdate конкретный случай, когда ваш PrimaryKey является Int:

using (var context = new BloggingContext()) 
{ 
    context.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified; 

    context.SaveChanges(); 
} 
+0

Как показывает ваш пример ссылочные объекты остаются в неизмененном состоянии? –

+0

Извините, что было неясно, я обновил свой ответ. Я привел пример из [там] (http://msdn.microsoft.com/en-us/data/jj592676.aspx), где они предупреждают разработчиков о реальном поведении модификации EntityState. – MaxSC

+0

Спасибо за ссылку, очень полезно – Lu4