Entity Framework 6: первый каскадный код кода

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

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

'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" перед удалением родителя?

Ответ 1

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

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

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

Чтобы работать, вы должны позволить базе данных обрабатывать удаление.

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

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

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

Ответ 2

Я думаю, что лучше переопределить метод 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);
}

Я установил true WillCascadeOnDelete (true)

Ответ 3

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

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

enter image description here

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