如何在 ef-core 的一对多关系中级联更新
How to cascade an update in a one to many relationship in ef-core
我有从Api申请人table到Apitable的多对一关系。我的 Api table 有以下字段:
Api: ID, name, date, isDeleted
ApiAppliant:Id,ApiID,ApplicantId,ApiRequestDate,gateId,isDeleted。
ApiId 是 ApiApplicant to Api table 中的外键。现在我的问题是,如果用户想删除一条 Api 记录,只有相关的 isDeleted 值应该更改为 1。然后在 ApiApplicant table 中,具有相同的 ApiId,isDeleted 值也应为 1。我是 ef-core 和 asp.net 的新手。如果有人通过显示示例代码向我提出解决方案,我将不胜感激。
您可以重写 DbContext 中的 SaveChangesAsync
方法以更新父实体和子实体中的 isDeleted
值 entities.Also,记得禁用 EF 核心的级联删除行为。
参考以下步骤:
1.Models:
public class Api
{
[Key]
public int ID { get; set; }
//other properties
public bool isDeleted { get; set; }
public List<ApiApplicant> ApiApplicants { get; set; }
}
public class ApiApplicant
{
[Key]
public int Id { get; set; }
public int? ApiID { get; set; }//set as nullable
//other properties
public bool isDeleted { get; set; }
[ForeignKey("ApiID")]
public Api Api { get; set; }
}
2.DbContext(禁用默认级联删除)
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Api> Apis { get; set; }
public DbSet<ApiApplicant> ApiApplicants { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Api>()
.HasMany(i => i.ApiApplicants)
.WithOne(c => c.Api)
.OnDelete(DeleteBehavior.Restrict);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
OnBeforeSaving();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
OnBeforeSaving();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
private void OnBeforeSaving()
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Deleted)
{
if (entry.Entity is Api )
{
entry.State = EntityState.Modified;
//change Api.isDeleted value to true
entry.CurrentValues["isDeleted"] = true;
//change navigations' isDeleted value to true
foreach (var c in entry.Collections)
{
if(c.Metadata.Name == "ApiApplicants")
{
foreach (var item in (IEnumerable)c.CurrentValue)
{
((ApiApplicant)item).isDeleted = true;
}
}
}
}
}
}
}
}
3.Delete 动作
[HttpPost]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var api = await _context.Apis.Include(a => a.ApiApplicants).FirstOrDefaultAsync(a=>a.ID == id);
_context.Apis.Remove(api);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
我有从Api申请人table到Apitable的多对一关系。我的 Api table 有以下字段: Api: ID, name, date, isDeleted ApiAppliant:Id,ApiID,ApplicantId,ApiRequestDate,gateId,isDeleted。 ApiId 是 ApiApplicant to Api table 中的外键。现在我的问题是,如果用户想删除一条 Api 记录,只有相关的 isDeleted 值应该更改为 1。然后在 ApiApplicant table 中,具有相同的 ApiId,isDeleted 值也应为 1。我是 ef-core 和 asp.net 的新手。如果有人通过显示示例代码向我提出解决方案,我将不胜感激。
您可以重写 DbContext 中的 SaveChangesAsync
方法以更新父实体和子实体中的 isDeleted
值 entities.Also,记得禁用 EF 核心的级联删除行为。
参考以下步骤:
1.Models:
public class Api
{
[Key]
public int ID { get; set; }
//other properties
public bool isDeleted { get; set; }
public List<ApiApplicant> ApiApplicants { get; set; }
}
public class ApiApplicant
{
[Key]
public int Id { get; set; }
public int? ApiID { get; set; }//set as nullable
//other properties
public bool isDeleted { get; set; }
[ForeignKey("ApiID")]
public Api Api { get; set; }
}
2.DbContext(禁用默认级联删除)
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Api> Apis { get; set; }
public DbSet<ApiApplicant> ApiApplicants { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Api>()
.HasMany(i => i.ApiApplicants)
.WithOne(c => c.Api)
.OnDelete(DeleteBehavior.Restrict);
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
OnBeforeSaving();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
OnBeforeSaving();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
private void OnBeforeSaving()
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Deleted)
{
if (entry.Entity is Api )
{
entry.State = EntityState.Modified;
//change Api.isDeleted value to true
entry.CurrentValues["isDeleted"] = true;
//change navigations' isDeleted value to true
foreach (var c in entry.Collections)
{
if(c.Metadata.Name == "ApiApplicants")
{
foreach (var item in (IEnumerable)c.CurrentValue)
{
((ApiApplicant)item).isDeleted = true;
}
}
}
}
}
}
}
}
3.Delete 动作
[HttpPost]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var api = await _context.Apis.Include(a => a.ApiApplicants).FirstOrDefaultAsync(a=>a.ID == id);
_context.Apis.Remove(api);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}