2014-01-23 4 views
11

Таким образом, здесь есть несколько подобных вопросов, но у меня все еще возникают проблемы с определением того, что именно мне не хватает в моем упрощенном сценарии.Entity Framework 6: Code First Cascade delete

Скажем, у меня есть следующие таблицы, хитро имени себя:

'JohnsParentTable' (Id, Description) 
'JohnsChildTable' (Id, JohnsParentTableId, Description) 

С результирующих классов выглядит как так

public class JohnsParentTable 
{ 
    public int Id { get; set; } 
    public string Description { get; set; } 
    public virtual ICollection<JohnsChildTable> JohnsChildTable { get; set; } 

    public JohnsParentTable() 
    { 
     JohnsChildTable = new List<JohnsChildTable>(); 
    } 
} 

internal class JohnsParentTableConfiguration : EntityTypeConfiguration<JohnsParentTable> 
{ 
    public JohnsParentTableConfiguration() 
    { 
     ToTable("dbo.JohnsParentTable"); 
     HasKey(x => x.Id); 
     Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
     Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50); 
    } 
} 

public class JohnsChildTable 
{ 
    public int Id { get; set; } 
    public string Description { get; set; } 
    public int JohnsParentTableId { get; set; } 
    public JohnsParentTable JohnsParentTable { get; set; } 
} 

internal class JohnsChildTableConfiguration : EntityTypeConfiguration<JohnsChildTable> 
{ 
    public JohnsChildTableConfiguration() 
    { 
     ToTable("dbo.JohnsChildTable"); 
     HasKey(x => x.Id); 
     Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
     Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50); 
     HasRequired(a => a.JohnsParentTable).WithMany(c => c.JohnsChildTable).HasForeignKey(a => a.JohnsParentTableId); 
    } 
} 

В базе данных у меня есть строка в родительской таблице с идентификатор 1 вместе с двумя строками в дочерней таблице, привязанными к этому родительскому элементу. Если я это сделаю:

var parent = db.JohnsParentTable.FirstOrDefault(a => a.Id == 1) 

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

var parent = new Data.Models.JohnsParentTable() { Id = 1 }; 
db.JohnsParentTable.Attach(parent); 
db.JohnsParentTable.Remove(parent); 

db.SaveChanges(); 

Entity Framework пытается выполнить следующие действия:

DELETE [dbo].[JohnsParentTable] 
WHERE ([Id] = @0) 
-- @0: '1' (Type = Int32) 
-- Executing at 1/23/2014 10:34:01 AM -06:00 
-- Failed in 103 ms with error: The DELETE statement conflicted with the REFERENCE constraint "FK_JohnsChildTable_JohnsParentTable". The conflict occurred in database "mydatabase", table "dbo.JohnsChildTable", column 'JohnsParentTableId'. 
The statement has been terminated. 

тогда мой вопрос, что именно я не хватает, чтобы обеспечить Entity Framework, знает, что он должен удалить строки «JohnsChildTable» перед удалением родителя?

ответ

11

Это зависит от того, хотите ли вы Entity Framework для удаления детей, или вы хотите, чтобы база данных, чтобы заботиться о нем.

Если вы хотите, чтобы EF создавал оператор удаления для всех дочерних элементов и выполнял их перед удалением родителя, сначала необходимо загрузить все дети в память.

Таким образом, вы не можете просто создать «фиктивный» объект только с заполненным ключом и ожидать, что дети будут удалены.

Для этого вам необходимо разрешить базе данных обрабатывать удаление.

У внешнего ключа на дочернем столе должно быть разрешено только каскадное удаление. Если это так, Entity Framework просто создает оператор удаления для родителя, и база данных знает также удалить детей.

Entity Framework создает внешний ключ с включенными по умолчанию каскадными удалениями, если требуется взаимодействие, как в вашем случае. (Внешний ключ не может быть нулевым).

Если вы создали базу данных самостоятельно, вы должны помнить ее включить.

-1

В Visual Studio откройте файл модели. Щелкните правой кнопкой мыши по отношениям «Родитель-ребенок» и выберите «Свойства».

В свойстве End1 OnDelete значение, вероятно, будет None. Другой вариант - Cascade; установите его на это. Теперь удаление родителя будет каскадом удалений для его детей.

enter image description here

Приветствия -

+8

вопрос OP для Code First. Это решение подходит только для модели First. – vidalsasoon

15

Я думаю, что лучше переопределить метод OnModelCreating и добавить этот код.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<JohnsChildTable>() 
       .HasRequired(t=>t.JohnsParentTable) 
       .WithMany(t=>t.JohnsChildTables) 
       .HasForeignKey(d=>d.JohnsParentTableId) 
       .WillCascadeOnDelete(true); 

      base.OnModelCreating(modelBuilder); 
} 

Я установил истинный WillCascadeOnDelete (истинного)

+0

Просто предупреждение: Насколько я знаю, код выше ** не делает * делает EF-каскад удалять дочерние элементы, которые не загружаются в память. – Riva

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