【问题标题】:Insert statement conflicts with FK constraint on ApplicationUsersInsert 语句与 ApplicationUsers 上的 FK 约束冲突
【发布时间】:2015-02-13 04:03:29
【问题描述】:

我有一个实体如下:

public class EntityX {
    public int Id { get; set; }
    ...
    [ForeignKey("Scheduled By")]
    public string ScheduledById { get; set; }
    public virtual ApplicationUser ScheduledBy { get; set; }
}

当我尝试向表中插入一个值时,我收到以下错误:

"INSERT 语句与 FOREIGN KEY 约束冲突 “FK_dbo.EntityX_dbo.ApplicationUsers_ScheduledById”。冲突 发生在数据库“DB”、表“dbo.ApplicationUsers”、“Id”列中。 声明已终止。”

首先想到的是 ApplicationUser 表是空的,因为 IdentityUser 表 (AspNetUsers) 包含所有值。但是,它的 TPH 和一个 Discriminator 列填充了 ApplicationUser 表名。

我已验证在数据库中发送时填充了正确的 ID(即它对应于实际的用户 ID),但无法弄清楚为什么会发生这种情况。

提前谢谢你。干杯!

更新:

“预定者”中的空格是错字。它被错误地复制了。实际代码已按照“ScheduledBy”所指出的那样编写。

更新 2:

问题似乎出在某个地方的上下文中。我有两个,一个从 DbContext 扩展的 DataContext 如下:

public class DataContext : DbContext
{
   public DbSet<EntityX> EntityXs { get; set; }
   ...
}

static DataContext()
{
     Database.SetInitializer<DataContext> (new CreateInitializer ());
}

public DataContext()
    : base("DataContext")
{

}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
    modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
    modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
    ...

}

还有一个,从 IdentityDbContext 扩展如下:

public class SecurityContext : IdentityDbContext<ApplicationUser>
{
    static SecurityContext()
    {
        Database.SetInitializer<SecurityContext> (new CreateInitializer ());
    }

    public SecurityContext()
        : base("SecurityContext")
    {
        Database.Initialize(force: true);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<IdentityUser>()
            .ToTable("AspNetUsers");
        modelBuilder.Entity<ApplicationUser>()
            .ToTable("AspNetUsers");

        modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
        modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
        modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });

        base.OnModelCreating(modelBuilder);
    }

有了这个,配置工作......但我遇到了一个问题,我在 AspNetUserRoles 表中出现了一个额外的 IdentityRole_Id,如本文所述:EF Code First Migration unwanted column IdentityRole_Id。为了解决这个问题,我在这里按照 Hao Kung 的建议:Create ASP.NET Identity tables using SQL script 并以这种方式更改了我的上下文的 OnModelCreating 方法:

数据上下文:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
    modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
    modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
}

还有 SecurityContext...

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        var user = modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers");
        user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
        user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
        user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
        user.Property(u => u.UserName).IsRequired();

        modelBuilder.Entity<ApplicationUser>().ToTable("AspNetUsers"); //Needed?

        modelBuilder.Entity<IdentityUserRole>()
            .HasKey(r => new { r.UserId, r.RoleId })
            .ToTable("AspNetUserRoles");

        modelBuilder.Entity<IdentityUserLogin>()
            .HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey })
            .ToTable("AspNetUserLogins");

        modelBuilder.Entity<IdentityUserClaim>()
            .ToTable("AspNetUserClaims");

        var role = modelBuilder.Entity<IdentityRole>()
            .ToTable("AspNetRoles");
        role.Property(r => r.Name).IsRequired();
        role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
}

虽然这样做可以正确构建数据库,但 AspNetUsers 表中的 Discriminator 列填充了“ApplicationUser”作为值,并且 AspNetUserRoles 中没有额外的列,但是任何将用户的 Id 值作为 FK 插入 EntityX 的尝试都会失败。

我完全迷路了。

【问题讨论】:

  • 尝试去掉FK属性中导航属性名称的空格-[ForeignKey("ScheduledBy")]
  • 对不起,我复制不正确。我的代码准确地说明了您在上面指定的内容。

标签: sql-server entity-framework ef-code-first asp.net-identity


【解决方案1】:

所以,事实证明,实体的设置方式没有任何问题。这是由于通过两种上下文迁移到同一个数据库时出现的一些问题。将它们合并为一个解决了这个问题。我已经在下面发布了我是如何解决问题的。希望这可以节省其他人的时间和痛苦。

public class SecurityContextContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<EntityX> EntityX { get; set; }
    ...

    static SecurityContext()
    {
        Database.SetInitializer<SecurityContext> (new CreateInitializer());
    }

    public SecurityContext()
        : base("SecurityContext")
    {
        Database.Initialize(force: true);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        var user = modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers");
        user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
        user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
        user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
        user.Property(u => u.UserName).IsRequired();
        user.HasKey(u => u.Id);

        var appUser = modelBuilder.Entity<ApplicationUser>().ToTable("AspNetUsers"); //Needed?
        appUser.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
        appUser.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
        appUser.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
        appUser.Property(u => u.UserName).IsRequired();

        modelBuilder.Entity<IdentityUserRole>()
            .HasKey(r => new { r.UserId, r.RoleId })
            .ToTable("AspNetUserRoles");

        modelBuilder.Entity<IdentityUserLogin>()
            .HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey })
            .ToTable("AspNetUserLogins");

        modelBuilder.Entity<IdentityUserClaim>()
            .ToTable("AspNetUserClaims");

        var role = modelBuilder.Entity<IdentityRole>()
            .ToTable("AspNetRoles");
        role.Property(r => r.Name).IsRequired();
        role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);

    }

此配置对我有用。尽管 ApplicationUser 表不是通过此映射生成的,但在 AspNetUsers 表中仍然创建了一个 Discriminator 列,其中填充了“ApplicationUser”。 AspNetUsers 表还获得了我在 ApplicationUser 类中定义的额外字段。 IdentityRole_Id 被消除,我能够分配角色并成功获得它们。 FK问题也解决了。一切都按预期进行。

【讨论】:

    【解决方案2】:

    如错误消息所示,您的外键需要与有效的实体属性相关联。如果将ForeignKey 属性放在外键属性上,则字符串参数表示关联导航属性的名称。删除空格以匹配导航属性的名称:

    public class EntityX
    {
        public int Id { get; set; }
         ...
        [ForeignKey("ScheduledBy")]
        public string ScheduledById { get; set; }
    
        public virtual ApplicationUser ScheduledBy { get; set; }
    }
    

    【讨论】:

    • 抱歉我的错误,我复制代码时不小心留下了一个空格。实际上,这两个词之间没有空格。它看起来就像您在上面指定的那样。现在将编辑问题。
    【解决方案3】:

    使用这个:

    public class EntityX
    {
      public int Id { get; set; }
    
      [ForeignKey("ScheduledBy")]
      public string ScheduledById { get; set; }
    
    
        [ForeignKey("ScheduledById")]
        [InverseProperty("EntityX_1")]
        public virtual ApplicationUser ScheduledBy{ get; set; }
    
    }
    
    public class ApplicationUser
    {
       public string ScheduledById { get; set; }
    
       .
       .
       .
        [InverseProperty("ScheduledBy")]
        public virtual ICollection<EntityX> EntityX_1{ get; set; }       
    }
    

    【讨论】:

    • 真的有必要设置逆属性吗?我对为什么这不起作用的猜测与其中一个上下文文件及其布局方式有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    相关资源
    最近更新 更多