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

c# entity-framework entity-framework-6 sql

Вопрос

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

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

'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»?

Принятый ответ

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

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

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

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

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

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

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


Популярные ответы

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



Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему