引用行删除后,外键未设置为null

时间:2019-12-20 16:05:04

标签: c# asp.net-core entity-framework-core

给出以下两个类:

public class PortalUser : IdentityUser
{
    public Guid? RefreshTokenId { get; set; }
    public RefreshToken RefreshToken { get; set; }

}

public class RefreshToken
{
    public Guid Id { get; set; }
    public string Token { get; set; }
    public string UserId { get; set; }
    public PortalUser User { get; set; }

    public RefreshToken(string token, string userId)
    {
        Token = token;
        UserId = userId;
    }
}

我建立了一对一的关系-用户可以只有一个刷新令牌,或者根本没有。请参阅下面的配置。

 public void Configure(EntityTypeBuilder<PortalUser> builder)
 {
     builder.HasOne(x => x.RefreshToken).WithOne(x => x.User)
                                  .HasForeignKey<PortalUser>(x => x.RefreshTokenId).OnDelete(DeleteBehavior.SetNull);
 }

public class RefreshTokenConfiguration : IEntityTypeConfiguration<RefreshToken>
{
    public void Configure(EntityTypeBuilder<RefreshToken> builder)
    {
        builder.ToTable("AspNetUserRefreshTokens");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Id).ValueGeneratedOnAdd();
        builder.Property(x => x.Token).IsRequired();
        builder.HasOne(x => x.User).WithOne(x => x.RefreshToken)
                                   .HasForeignKey<RefreshToken>(x => x.UserId).OnDelete(DeleteBehavior.Cascade);

    }
}

现在,当删除用户时,级联删除效果很好-刷新令牌也被删除,但是当我删除单个刷新令牌时,PortalUser中的FK仍为SET。

这对我来说似乎不对,知道我在做什么错吗?

1 个答案:

答案 0 :(得分:1)

我试图重现您的问题,据我所知您的配置正确。 您可能会错过的一件事(或只是未包括在问题中)是如何将EntityTypeBuilder<PortalUser>连接到数据库上下文中。我成功完成了以下配置:

DbContext.cs

public class DbContext: IdentityDbContext<PortalUser>
{
    public DbSet<RefreshToken> AspNetUserRefreshTokens { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder builder)
    {
        builder.UseSqlServer("needs a connection string");

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfiguration(new RefreshTokenConfiguration());
        modelBuilder.ApplyConfiguration(new PortalUserConfiguration()); // i suspect this piece can be your issue, check if you've got it hooked up
    }

    public class PortalUserConfiguration : IEntityTypeConfiguration<PortalUser>
    {
        public void Configure(EntityTypeBuilder<PortalUser> builder)
        {
            builder.HasOne(x => x.RefreshToken)
                .WithOne(x => x.User)
                .HasForeignKey<PortalUser>(x => x.RefreshTokenId)
                .OnDelete(DeleteBehavior.SetNull);
        }
    }

    public class RefreshTokenConfiguration : IEntityTypeConfiguration<RefreshToken>
    {
        public void Configure(EntityTypeBuilder<RefreshToken> builder)
        {
            builder.ToTable("AspNetUserRefreshTokens");
            builder.HasKey(x => x.Id);
            builder.Property(x => x.Id).ValueGeneratedOnAdd();
            builder.Property(x => x.Token).IsRequired();
            builder.HasOne(x => x.User).WithOne(x => x.RefreshToken)
                .HasForeignKey<RefreshToken>(x => x.UserId).OnDelete(DeleteBehavior.Cascade);
        }
    }
}

我的测试台看起来像这样:

Program.cs

class Program
{
    static void Main(string[] args)
    {
        var ctx = new DbContext();
        //ctx.Database.EnsureCreated(); // you probably don't need this step
        var user = new PortalUser();
        var t = new RefreshToken("test", user.Id);
        user.RefreshToken = t;
        ctx.Users.Add(user);
        ctx.SaveChanges();

        var token = ctx.AspNetUserRefreshTokens.Find(t.Id);
        ctx.Entry(token).State = EntityState.Deleted;
        ctx.SaveChanges();

        var u = ctx.Users.Find(user.Id);
        Console.Write($"RefreshTokenId {u.RefreshTokenId}");
        Console.ReadKey();
    }
}