2015-04-21 4 views
1

Я использую codeFirst и независимые ассоциации в EF 6.1 EF не хочет обновлять отдельные объекты. Attach и StateModified не помогают связанным (FK) объектам. Добавление новых объектов и восходящих не связанных свойств работает правильно. Где проблема?EF не обновляет связанные объекты, только простые поля

У меня есть основная сущность CoachTransaction:

public class CoachTransaction : BaseEntity 
    { 
     public DateTime? TransactionDate { get; set; } 

     public int? Season { get; set; } 
     public virtual CoachPosition Position { get; set; } 
     public virtual Institution StartInstitution { get; set; } 
     public virtual Institution EndInstitution { get; set; }  
    } 

Mapping для него:

public MapCoachTransaction() 
     { 
      ToTable("CoachTransactions"); 
      HasKey(x => x.Id); 

      Property(x => x.Id).HasColumnName("TransactionId"); 
      Property(x => x.TransactionDate); 

      HasOptional(x => x.Position).WithMany().Map(x => x.MapKey("CoachPositionId")); 
      HasOptional(x => x.StartInstitution).WithMany().Map(x => x.MapKey("StartInstitutionId")); 
      HasOptional(x => x.EndInstitution).WithMany().Map(x => x.MapKey("EndInstitutionId")); 
     } 

Связанных Сущности выглядят следующим образом:

public class Institution : BaseEntity 
    { 
     public virtual InstitutionType InstitutionType { get; set; } 
     public string Name { get; set; } 
     public string ImageUrl { get; set; }   
    } 

Mapping для родственных организаций:

public MapInstitution() 
     { 
      ToTable("Institution"); 
      HasKey(x => x.Id); 
      Property(x => x.Id).HasColumnName("InstitutionId"); 
      HasOptional(x => x.InstitutionType).WithMany(x => x.Institutions).Map(x => x.MapKey("InstitutionTypeId")); 
      Property(x => x.Name).HasColumnName("InstitutionName"); 
      Property(x => x.ImageUrl).HasColumnName("InstitutionImageUrl"); 
     } 

Использование как это:

   using (var context = new CoachDBContext()) 
       { 
        IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context); 
        coachTransaction.Seasion = 100; // this works 
        coachTransaction.EndInstitution = newInstitution; this doesnt' 
        repository.Update(coachTransaction); // coachTransaction comes from POST to Controller 
        repository.Save(); 
       } 

и repository.Updarte метод использует Attach конечно:

public virtual void Update(TEntity entityToUpdate) 
     { 
      EntitySet.Attach(entityToUpdate); 
      dbContext.Entry(entityToUpdate).State = EntityState.Modified; 
     } 

При этом настройки запроса SQL выглядит следующим образом:

exec sp_executesql N'UPDATE [dbo].[CoachTransactions] 
SET [TransactionDate] = @0, [Season] = @1 
WHERE ([TransactionId] = @2) 
',N'@0 datetime2(7),@1 int,@2 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=24 

Таким образом, мой объект endInstitution не обновляется.

Но если я прошу это лицо перед сохранением:

using (var context = new CoachDBContext()) 
        { 
         IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context); 
         var coachTransaction = repository.GetById(coachTransaction.Id) // this fixes problem, but not acceptable in this case 
         coachTransaction.Season = 100; 
         coachTransaction.EndInstitution = newInstitution; // now this will work 
         repository.Update(coachTransaction); // coachTransaction comes from POST to Controller 
         repository.Save(); 
        } 

И SQL будет содержать ключи, относящиеся как:

exec sp_executesql N'UPDATE [dbo].[CoachTransactions] 
SET [TransactionDate] = @0, [Season] = @1, 

[EndInstitution] = @2 

WHERE ([TransactionId] = @3) 
',N'@0 datetime2(7),@1 int,@2 int, @3 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=2,@3=24 

P.S.

Кроме того, использование ForeignKey Ассоциация approeach исправляет эту проблему с mappting так:

Property(x => x.PositionId).HasColumnName("CoachPositionId"); 
      Property(x => x.StartInstitutionId).HasColumnName("StartInstitutionId"); 
      Property(x => x.EndInstitutionId).HasColumnName("EndInstitutionId"); 
      HasRequired(x => x.Position).WithMany().HasForeignKey(x => x.PositionId); 
      HasRequired(x => x.StartInstitution).WithMany().HasForeignKey(x => x.StartInstitutionId); 
      HasRequired(x => x.EndInstitution).WithMany().HasForeignKey(x => x.EndInstitutionId); 

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

updatingObject.EndInstitution = existingInstitution2; 
updatingObject.EndInstitutionId = existingInstitution2.Id; 

INSEAD одного звонка: updatingObject.EndInstitution = existingInstitution2;

Также он требует бесполезных свойств Id. Это выглядит неправильно с моей точки зрения. Есть ли какое-то решение?

+0

Правильно, вам нужно будет сделать SetValues ​​для ребенка или использовать GraphDiff. http://blog.maskalik.com/entity-framework/2013/12/23/entity-framework-updating-database-from-detached-objects/ –

+0

Но как можно создать общий репозиторий, который сохраняет и конкретизирует свойства которые необходимо обновить с помощью SetValue? –

+0

Итак, я попробовал: updateEntity.EndInstitution = endInstitution; repository.Update (updateEntity); dbContext.Entry (updateEntity.EndInstitution) .CurrentValues.SetValues ​​(endInstitution); Это не работает. –

ответ

4

Метод Attach не прикрепляет сущности. Для этого вам необходимо привязать все цели иждивенцев, которые вы хотите обновить. Вы можете использовать GraphDiff, чтобы обновить полный график без привязки объектов. Использование что-то вроде этого: используя (вар кон

text = new TestDbContext()) 
{ 
    // Update the company and state that the company 'owns' the collection Contacts. 
    context.UpdateGraph(company, map => map 
     .OwnedCollection(p => p.Contacts, with => with 
      .AssociatedCollection(p => p.AdvertisementOptions)) 
     .OwnedCollection(p => p.Addresses) 
    ); 

    context.SaveChanges(); 
} 

Это brief introduction к каркасу.

Кроме того, я был обзор исходного кода Entity Framework и нашел способ действительно обновить объект, если вы знаете ключевое свойство в другом случае вам нужно проверить выполнение AddOrUpdate:

public void Update(T item) 
{ 
    var entity = _collection.Find(item.Id); 
    if (entity == null) 
    { 
     return; 
    } 

    _context.Entry(entity).CurrentValues.SetValues(item); 
} 

Надеюсь, эта помощь!

+0

Но как можно использовать этот метод в общем репозитории, когда свойства (например, p.Contacts в вашем примере) различны? –

+1

Этот образец из введения DiffGraph. Чтобы достичь этого с помощью общего репозитория, вам нужно просмотреть структуру ИЛИ искать обходное решение, потому что EF не имеет обновления так, как вам нужно – Miguel

+0

Какое ORM имеет лучшее обновление? Есть ли у Nhibernate? другие рамки? Потому что для меня очень странно иметь версию 6 и не выполнять базовые операции. –

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