问题描述
我正在尝试从数据库中删除 User
,User
有它自己的 Recipes
。即使我在模型构建器中配置了级联删除,它也不起作用。
我得到的错误是:
sqlException:DELETE 语句与 REFERENCE 约束“FK_Recipes_AspNetUsers_ApplicationUserId”冲突。数据库“master”、表“dbo.Recipes”、“ApplicationUserId”列发生冲突。
AplicationUser.cs:
namespace WebApplication.Models
{
public class ApplicationUser : IdentityUser
{
public ICollection<Recipe> Recipes { get; set; }
}
}
Recipe.cs
namespace WebApplication.Models
{
public class Recipe
{
[Key]
public Guid Id { get; set; }
[required]
public string RecipeName { get; set; }
[required]
public string RecipeContent { get; set; }
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
}
}
ApplicationDbContext.cs
namespace WebApplication.Models
{
public class ApplicationDbContext : IdentityDbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>().HasMany(e => e.Recipes).WithOne(e => e.ApplicationUser)
.OnDelete(DeleteBehavior.ClientCascade);
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Recipe> Recipes { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
}
}
UserController.cs
public IActionResult Delete(string id)
{
var user = _applicationDbContext.Users
.Where(u => u.Id == id).FirstOrDefault();
return View(user);
}
[HttpPost]
public IActionResult Delete(ApplicationUser appuser)
{
var user = _applicationDbContext.Users
.Where(u => u.Id == appuser.Id).FirstOrDefault();
_applicationDbContext.Users.Remove(user);
_applicationDbContext.SaveChanges();
return RedirectToAction("Index");
}
配置 modulbuilder 似乎对几乎所有人来说都是解决方案,但肯定对我不起作用。
解决方法
ClientCascade
只会删除由 DbContext 跟踪的相关实体,而 Cascade
还会在数据库中的 FK 约束上设置删除孤儿,如果设置了 EF 来管理模式。
您需要确保 hte DbContext 正在跟踪要删除的相关实体:
var user = _applicationDbContext.Users
.Include(x => x.Recipies)
.Where(u => u.Id == appuser.Id)
.SingleOrDefault();
这可确保 DbContext 知道相关实体,并应在删除用户之前删除这些实体。您还需要注意可能引用用户记录或 FK 的任何其他实体。例如,如果其他记录正在跟踪类似 CreatedBy 的内容,那么这些记录可能会被设置为将 FK 返回给用户。依赖 ClientCascade
在这里可能会出现问题,级联删除可能不可取,而是选择软删除模型。 (即 ApplicationUser 上的 IsActive
标志而不是删除行)
此外,避免使用 First
方法,除非您需要多行并且特别想要第一行。这些方法也只能与 OrderBy
方法结合使用。如果您希望有 1 行,请使用 Single
。如果您希望有 0 或 1 行,请使用 SingleOrDefault
。这有助于确保任何意外的数据状态都会导致有意义的异常,而不是默默地做一些意外的事情。
我设法通过更改这一行来解决这个问题: var user = _applicationDbContext.Users.Where(u => u.Id == appuser.Id).FirstOrDefault(); 对此: var user = _userManager.Users.Include(e=>e.Recipes).Where(u => u.Id == appuser.Id).FirstOrDefault();