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。