我有一个实体如下:
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的尝试都会失败。
我完全失去了。
答案 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; }
}