最近忙于.NET COERE WEB API的学习,遇到EFCORE中关于级联删除的知识,正好使用postman实践一下。
理论知识
(这块直接贴的官方文档,官方文档很清楚了)
级联删除通常在数据库术语中用来描述一种允许在删除某行时自动触发删除相关行的特性。 EF Core 删除行为还介绍了一个密切相关的概念,即子实体与父实体的关系已断开时自动删除该子实体,这通常称为“删除孤立项”。
EF Core 实现多种不同的删除行为,并允许配置各个关系的删除行为。 EF Core 还实现基于关系的需求为每个关系自动配置有用的默认删除行为的约定。
删除行为在 DeleteBehavior 枚举器类型中定义,并且可以传递到 OnDelete Fluent API 来控制是主体/父实体的删除还是依赖实体/子实体关系的断开会对依赖实体/子实体产生副作用。
删除主体/父实体或断开与子实体的关系时有三个 EF 可执行的操作:
仅当使用 EF Core 删除主体且将依赖实体加载到内存中(即对于跟踪的依赖项)时才应用 EF Core 模型中配置的删除行为。 需要在数据库中设置相应的级联行为以确保未由上下文跟踪的数据已应用必要的操作。 如果使用 EF Core 创建数据库,将为你设置此级联行为。
对于上述第二个操作,如果外键不可以为 null,则将外键值设置为 null 是无效的。 (不可为 null 的外键相当于必需关系。)在这些情况下,EF Core 会跟踪外键属性是否已被标记为 null,直到调用 SaveChanges,此时会引发异常,因为无法将更改永久保存到数据库中。 这类似于从数据库中获取约束冲突。
有四个删除行为,如下表中列出。
对于可选关系(可以为 null 的外键),可以保存 null 外键值,从而产生以下影响:
行为名称 | 对内存中的依赖项/子项的影响 | 对数据库中的依赖项/子项的影响 |
---|---|---|
Cascade | 删除实体 | 删除实体 |
ClientSetNull(默认) | 外键属性设置为 null | None |
SetNull | 外键属性设置为 null | 外键属性设置为 null |
Restrict | None | None |
对于必选关系(不可为 null 的外键),_不可以_保存 null 外键值,从而产生以下影响:
行为名称 | 对内存中的依赖项/子项的影响 | 对数据库中的依赖项/子项的影响 |
---|---|---|
Cascade(默认) | 删除实体 | 删除实体 |
ClientSetNull | SaveChanges 引发异常 | None |
SetNull | 引发 SaveChanges | SaveChanges 引发异常 |
Restrict | None | None |
在上表中,“无” 可能会造成约束冲突。 例如,如果已删除主体/子实体,但不执行任何操作来更改依赖项/子项的外键,则由于发生外键约束冲突,数据库将可能会引发 SaveChanges。
高级别:
在 EF Core(与 EF6 不同)中,不会立即产生级联影响,而是仅在调用 SaveChanges 时产生。
EF Core 2.0 中的更改: 在之前的版本中,“Restrict”将导致跟踪的依赖实体中的可选外键属性设置为 null,并且是可选关系的默认删除行为 。 在 EF Core 2.0 中,引入了“ClientSetNull” 以表示该行为,并且它会成为可选关系的默认值。 “Restrict” 的行为已调整为永远不会对依赖实体产生副作用
公司实体以及雇员实体
public class Company
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Introduction { get; set; }
public ICollection employees { get; set; }
}
public class Employee
{
public Guid Id { get; set; }
public Guid CompanyId { get; set; }
public string EmployeeNo { get; set; }
public string FristName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public Company Company { get; set; }
}
DBCONTEXT配置
modelBuilder.Entity().
HasMany(x => x.employees).
WithOne(x => x.Company).
HasForeignKey(x => x.CompanyId).
OnDelete(DeleteBehavior.Cascade);
数据库操作
public void DeleteCompany(Company company)
{
if (company == null)
{
throw new ArgumentNullException(nameof(company));
}
_dbContext.Companies.Remove(company);
}
API接口
[HttpDelete("{companyId}")]
public async Task DeleteCompany(Guid companyId)
{
if (companyId == Guid.Empty)
{
throw new ArgumentNullException(nameof(companyId));
}
var company = await _repository.GetCompanyAsnc(companyId);
if (company == null)
{
return NotFound();
}
_repository.DeleteCompany(company);
await _repository.SaveChangeAsnc();
return NoContent();
}
POSTMAN请求URL示例
https://localhost:5001/api/companies/conmpanyId