EF Core API在数据库中为EntityState
已删除的实体构建并执行DELETE语句。删除EF Core中有连接和无连接的场景中的实体没有区别。EF Core可以轻松地从上下文中删除实体,而后者又将使用以下方法删除数据库中的记录。
DbContext方法 | DbSet方法 | 描述 |
---|---|---|
DbContext.Remove | DbSet.Remove | 将指定的实体附加到处于DbContext 已删除状态并开始跟踪它。 |
DbContext.RemoveRange | DbSet.RemoveRange | 将实体的集合或数组附加到处于DbContext 已删除状态并开始跟踪它们。 |
以下示例演示了在断开连接的方案中删除实体的不同方法。
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();
}
在上面的示例中,使用or 方法从上下文中删除Studnet
具有valid 的实体。数据将从数据库中删除。上面的示例在数据库中执行以下delete命令:StudentIdRemove()RemoveRange()SaveChanges()
exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Students]
WHERE [StudentId] = @p0;
SELECT @@ROWCOUNT;
',N'@p0 int',@p0=1
go
备注:该DbContext.Remove()
和DbContext.RemoveRange()
方法在EF核心新引入使删除操作简便。
异常:
如果相应数据库表中不存在Remove()
或RemoveRange()
方法中指定实体中的Key值,则EF Core将引发异常:以下示例将引发异常。
var student = new Student() {
StudentId = 50
};
using (var context = new SchoolContext()) {
context.Remove<Student>(student);
context.SaveChanges();
}
在上面的示例中,数据库中不存在Student
with StudentId = 50
。因此,EF Core将抛出以下内容DbUpdateConcurrencyException
:
数据库操作预计会影响1行,但实际上会影响0行。自加载实体以来,数据可能已被修改或删除。
因此,您需要适当地处理上述异常,或者在删除之前确保数据库中存在具有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("Record does not exist in the database");
}
catch (Exception ex)
{
throw;
}
}
删除多个记录
您可以使用DbContext.RemoveRange()
or 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);
// 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
删除相关数据
如果实体与其他实体(例如一对一或一对多)有关系,则删除根实体时删除相关数据取决于关系的配置方式。
例如,考虑到Student
和Grade
实体之间存在一对多的关系。特定的学生记录会很多GradeId
。如果我们尝试删除Students
数据库中具有相关记录的成绩,EF将引发参考完整性错误。要解决此问题,可以使用Fluent API定义参照约束操作选项。例如,您可以为关系配置级联删除选项,如下所示。
modelBuilder.Entity<Student>()
.HasOne<Grade>(s => s.Grade)
.WithMany(g => g.Students)
.HasForeignKey(s => s.GradeId)
.OnDelete(DeleteBehavior.Cascade);
现在,如果删除Grade
实体,那么所有相关Student
记录也将在数据库中删除。
有在EF核心提供的其他参照约束行动选项,如SetNull
,ClientSetNull
和Restrict
。