在ApplicationUsers上插入与FK约束的语句冲突

时间:2015-02-13 04:03:29

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

我有一个实体如下:

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&#34 ;.冲突   发生在数据库" DB",table" dbo.ApplicationUsers",column' Id'。   该声明已被终止。"

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

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

提前谢谢你。干杯!

更新

"预定的空间"是一个错字。它被错误地复制了。实际代码按指出编写了#34; 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。为了解决这个问题,我在这里遵循了郝公的建议:Create ASP.NET Identity tables using SQL script并且改变了我的背景&#39; OnModelCreating方法这样:

的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 });
}

和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列填充了&#34; ApplicationUser&#34;作为值并且没有AspNetUserRoles中的额外列,任何将用户的Id值作为FK插入EntityX的尝试都会失败。

我完全失去了。

3 个答案:

答案 0 :(得分:1)

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

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

    public virtual ApplicationUser ScheduledBy { get; set; }
}

答案 1 :(得分:1)

因此,事实证明实体的设置方式没有任何问题。这是由于在通过两个上下文迁移到同一个DB时出现的一些问题。将它们合并为一个固定的问题。我已经发布了如何解决以下问题的方法。希望这可以节省别人的时间和折磨。

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 :(得分:0)

使用它:

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; }       
}