Entity Framework Core系列教程-18-斷開模式下刪除數據

Entity Framework Core 斷開模式下刪除數據

EF Core API會爲EntityState爲Deleted的實體建立並執行數據庫中的DELETE語句。在EF Core中已連接和已斷開連接的場景中刪除實體沒有什麼區別。 EF Core使得從上下文中刪除實體變得容易,而上下文又將使用以下方法刪除數據庫中的記錄。

DbContext 方法 DbSet 方法 描述
DbContext.Remove DbSet.Remove 將指定的實體附加到狀態爲“已刪除”的DbContext並開始對其進行跟蹤
DbContext.RemoveRang DbSet.RemoveRange 將實體的集合或數組附加到具有Deleted狀態的DbContext並開始跟蹤它們

以下示例演示了在斷開連接的場景中刪除實體的不同方法:

// entity to be deleted
var student = new Student() {
        StudentId = 1
};

using (var context = new SchoolContext()) 
{
    context.Remove<Student>(student);
   
    // or the followings are also valid
    // context.RemoveRange(student);
    //context.Students.Remove(student);
    //context.Students.RemoveRange(student);
    //context.Attach<Student>(student).State = EntityState.Deleted;
    //context.Entry<Student>(student).State = EntityState.Deleted;
    
    context.SaveChanges();
}

在上面的示例中,使用Remove()或RemoveRange()方法從上下文中刪除了具有有效StudentId的Studnet實體。數據將從SaveChanges()上的數據庫中刪除。上面的示例在數據庫中執行以下delete命令:

exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Students]
WHERE [StudentId] = @p0;
SELECT @@ROWCOUNT;
',N'@p0 int',@p0=1
go

注意:EF Core中新引入了DbContext.Remove()和DbContext.RemoveRange()方法,以簡化刪除操作。

異常

如果相應數據庫表中不存在Remove()或RemoveRange()方法中指定實體中的Key值,則EF Core將引發異常:以下示例將引發異常。

var student = new Student() {
    StudentId = 50
};

using (var context = new SchoolContext()) {
    context.Remove<Student>(student);
    context.SaveChanges();
}

在上面的示例中,數據庫中不存在StudentId = 50的Student。因此,EF Core將引發以下DbUpdateConcurrencyException:

Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.
數據庫操作預期會影響1行,但實際上會影響0行。自加載實體以來,數據可能已被修改或刪除。

因此,您需要適當地處理以上異常,或者在刪除ID之前確保數據庫中存在具有ID的對應數據。

var student = new Student() {
    StudentId = 50
};

using (var context = new SchoolContext()) 
{
    try
    {
        context.Remove<Student>(deleteStudent);
        context.SaveChanges();
    }    
    catch (DbUpdateConcurrencyException ex)
    {
        throw new Exception("數據庫中不存在此紀錄");
    }
    catch (Exception ex)
    {
        throw;
    }
}

刪除多條記錄

您可以使用DbContext.RemoveRange()或DbSet.RemoveRange()方法一次性刪除多個實體。

IList<Student> students = new List<Student>() {
    new Student(){ StudentId = 1 },
    new Student(){ StudentId = 2 },
    new Student(){ StudentId = 3 },
    new Student(){ StudentId = 4 }
};

using (var context = new SchoolContext()) 
{
    context.RemoveRange(students);
    
    // or
    // context.Students.RemoveRange(students);
    
    context.SaveChanges();
}

上面的示例將在單個數據庫行程中從數據庫中刪除4條記錄。因此,EF Core改善了性能。

exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Students]
WHERE [StudentId] = @p0;
SELECT @@ROWCOUNT;


DELETE FROM [Students]
WHERE [StudentId] = @p1;
SELECT @@ROWCOUNT;

DELETE FROM [Students]
WHERE [StudentId] = @p2;
SELECT @@ROWCOUNT;


DELETE FROM [Students]
WHERE [StudentId] = @p3;
SELECT @@ROWCOUNT;

',N'@p0 int,@p1 int',@p0=1,@p1=2,@p2=3,@p3=4
go

刪除關聯數據

如果一個實體與其他實體有一對一或一對多的關係,則在刪除根實體時刪除相關數據取決於如何配置該關係。
例如,考慮“學生”和“年級”實體之間存在一對多關係。特定的GradeId將有許多學生記錄。如果我們嘗試刪除數據庫中具有相關學生記錄的成績,EF將拋出參考完整性錯誤。要解決此問題,您可以使用Fluent API定義引用約束操作選項。例如,您可以爲該關係配置一個級聯刪除選項,如下所示。

modelBuilder.Entity<Student>()
    .HasOne<Grade>(s => s.Grade)
    .WithMany(g => g.Students)
    .HasForeignKey(s => s.GradeId)
    .OnDelete(DeleteBehavior.Cascade);

現在,如果您刪除成績實體,那麼所有相關的學生記錄也將在數據庫中刪除。
EF Core中還有其他引用約束操作選項,例如SetNull,ClientSetNull和Restrict。

發佈了153 篇原創文章 · 獲贊 44 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章