2013-03-05 11 views
30

dokumentacja EntityFramework stwierdza, że ​​następujące zachowanie jest możliwe:EntityFramewok: Jak skonfigurować Cascade-Delete aby unieważnić klucze obce

If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.

(od http://msdn.microsoft.com/en-us/jj591620)

jednak, że nie może osiągnąć takiego zachowania.

Mam następujące podmiotów określonych w code-first:

public class TestMaster 
{ 
    public int Id { get; set; } 
    public string Name { get; set; }   
    public virtual ICollection<TestChild> Children { get; set; }  
} 

public class TestChild 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual TestMaster Master { get; set; } 
    public int? MasterId { get; set; } 
} 

Oto Płynna konfiguracja mapowania API:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<TestMaster>() 
        .HasMany(e => e.Children) 
        .WithOptional(p => p.Master).WillCascadeOnDelete(false); 

     modelBuilder.Entity<TestChild>() 
        .HasOptional(e => e.Master) 
        .WithMany(e => e.Children) 
        .HasForeignKey(e => e.MasterId).WillCascadeOnDelete(false); 
    } 

klucz obcy jest pustych, nieruchomości nawigacja jest odwzorowany jako opcjonalne, więc Oczekuję, że kaskadowe usuwanie zadziała jak opisano jako MSDN - tj. Anuluje MasterID wszystkich dzieci, a następnie usuwa obiekt główny.

Ale kiedy rzeczywiście starają się usuwać, otrzymuję błąd naruszenia FK:

using (var dbContext = new TestContext()) 
     { 
      var master = dbContext.Set<TestMaster>().Find(1); 
      dbContext.Set<TestMaster>().Remove(master); 
      dbContext.SaveChanges(); 
     } 

Na SaveChanges() zgłasza następujące:

System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while updating the entries. See the inner exception for details. 
----> System.Data.UpdateException : An error occurred while updating the entries. See the inner exception for details. 
----> System.Data.SqlClient.SqlException : The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.TestChilds_dbo.TestMasters_MasterId". The conflict occurred in database "SCM_Test", table "dbo.TestChilds", column 'MasterId'. 
The statement has been terminated. 

Czy robię coś źle albo ja źle zrozumieć, co mówi MSDN?

Odpowiedz

42

Działa tak, jak opisano, ale artykuł na temat MSDN brakuje, aby podkreślić, że działa tylko wtedy, gdy dzieci są ładowane do kontekstu, a także, nie tylko jednostki nadrzędnej. Tak więc, zamiast korzystania Find (który tylko ładuje rodzica) należy użyć chętny załadunek z Include (lub w inny sposób, aby załadować dzieci w kontekście):

using (var dbContext = new TestContext()) 
{ 
    var master = dbContext.Set<TestMaster>().Include(m => m.Children) 
     .SingleOrDefault(m => m.Id == 1); 
    dbContext.Set<TestMaster>().Remove(master); 
    dbContext.SaveChanges(); 
} 

spowoduje to usunięcie mistrza z bazy danych, ustaw wszystkie klucze obce w jednostkach Child na null i napisz instrukcje UPDATE dla potomków do bazy danych.

+7

pogrubiony tekst mnie uratował. Leniwe ładowanie jest świetne, ale upewnij się, że obiekty podrzędne są ładowane przed usunięciem ... – amaters

+0

Próbuję tego przykładu. Ale dostałem błąd w "uwzględnij". mówi "nie można przekonwertować wyrażenia lamba na typ" string ", ponieważ nie jest to typ delegata" .... Czego mi brakuje? Dzięki – Diego

0

Po wykonaniu wspaniałej odpowiedzi @ Slauma wciąż otrzymywałem ten sam błąd co OP.

Więc nie bądź tak naiwny jak ja i myśl, że poniższe przykłady zakończą się z tym samym rezultatem.

dbCtx.Entry(principal).State = EntityState.Deleted; 
dbCtx.Dependant.Where(d => d.PrincipalId == principalId).Load(); 

// code above will give error and code below will work on dbCtx.SaveChanges() 

dbCtx.Dependant.Where(d => d.PrincipalId == principalId).Load(); 
dbCtx.Entry(principal).State = EntityState.Deleted; 

najpierw załadować dzieci w odpowiednim kontekście przed ustawiania stanu jednostki do usunięcia (jeśli robisz to w ten sposób).

Powiązane problemy