【问题标题】:How to link one-to-one relationship when fk is different from pk - EntityFramework当fk与pk不同时如何链接一对一的关系 - EntityFramework
【发布时间】:2017-07-25 19:33:15
【问题描述】:

我的数据库中有一个自定义用户表,我想与 aspnetusers 表创建一对一的关系,这样当我注册新客户时,通过 UserManager 的 applicationuser 类应该添加 用户名、电子邮件、密码和学校代码 到用户表,并在自己的表中添加一个 fk。有没有实现这种场景的教程/示例?

我正在尝试添加与我的用户表的一对一关系,但 fk 与 pk 不同

  • 用户表 [列]
    • 用户名
    • 密码
    • 学校代码
    • 用户 ID [pk]

ASPNETUsers 表 [标准列]

  • 标识,[pk]
  • 用户名,
  • 密码哈希,
  • 安全邮票,
  • 判别器,
  • 电子邮件,
  • 已确认电子邮件,
  • 电话号码,
  • 已确认电话号码,
  • 启用双因素,
  • Lo​​ckoutEndDateUtc,
  • Lo​​ckoutEnabled,
  • AccessFailedCount
  • userId [fk 到用户表]

我在 ApplicationUser 类中添加了属性

public class ApplicationUser : IdentityUser
{
    public virtual User user { get; set; }
    public int UserID { get; set; }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<ApplicationUser>()
          .HasRequired(i => i.user).WithRequiredDependent(i => i.appUser);
      }

}

 public class User
{
    public int UserID { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public virtual ApplicationUser appUser { get; set; }
}

我还需要做什么,是否正确?实体框架如何与这个一起工作?

我试图在这里解释我的应用程序结构:

更新 在运行它给我错误 MySql.Data.MySqlClient.MySqlException:“on 子句”中的未知列“Extent8.appUser_Id”

如果我定义

modelBuilder.Entity<ApplicationUser>().HasKey(u => u.UserID);

OnModelCreating 中,它会尝试通过此 UserID 链接 AspNetRoles 和 Claims 等表,当然会崩溃。

ApplicationUser_Claims_Source_ApplicationUser_Claims_Target: : 引用约束的Dependent Role中所有属性的类型必须与Principal Role中对应的属性类型相同。实体“IdentityUserClaim”上的属性“UserId”类型与引用约束“ApplicationUser_Claims”中实体“ApplicationUser”上的属性“UserID”类型不匹配。 ApplicationUser_Logins_Source_ApplicationUser_Logins_Target: : 引用约束的Dependent Role中所有属性的类型必须与Principal Role中对应的属性类型相同。实体“IdentityUserLogin”上的属性“UserId”类型与引用约束“ApplicationUser_Logins”中实体“ApplicationUser”上的属性“UserID”类型不匹配。 ApplicationUser_Roles_Source_ApplicationUser_Roles_Target: : 一个参照约束的Dependent Role中所有属性的类型必须与Principal Role中对应的属性类型相同。实体“IdentityUserRole”上的属性“UserId”类型与引用约束“ApplicationUser_Roles”中实体“ApplicationUser”上的属性“UserID”类型不匹配。

【问题讨论】:

  • 完成。我希望你有足够的耐心,理解我的解释并阅读我推荐的链接。祝你好运!!!
  • 非常感谢 Alisson!我被困两天了!!

标签: asp.net-mvc entity-framework-6 asp.net-identity entity-relationship dbcontext


【解决方案1】:

简而言之,EF 的一对一关系如何工作...

使用 一对一 关系时,Entity Framework 使用父级在子级中的 Id 列作为父级的 FK,它不会为 FK 创建第二列,因为这将被视为 一对多 关系,因为第二列将允许父 Id 存在于许多子条目中,而作为 FK 的 PK 则不会。

我应该如何配置这两个键?

由于您的ApplicationUser 继承自IdentityUser,它将使用它现有的属性和关系。它已经定义了一个Id 列,因此不需要创建UserId,也不需要尝试使UserId 成为key 属性。您应该使用现有的Id 列,默认情况下为string,并且看起来您现有的User 表有一个integer PK,因此它们不匹配。

然而,这并不是世界末日。 Identity 的内置实现使用 string 作为其类(AspNetUsers、AspNetRoles 等...)的键,但它们允许我们使用另一种类型的主键。

那么……我该怎么办?

Identity 为每个表定义了两个类,因此有两个IdentityUser 类,两个IdentityRole,以此类推。一个是基础泛型类,它接受一些泛型。另一个是该基类的内置实现,它提供这些泛型类型。

这个基类如下所示:

public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
        where TLogin : IdentityUserLogin<TKey>
        where TRole : IdentityUserRole<TKey>
        where TClaim : IdentityUserClaim<TKey>

第一个泛型类型是TKey,它定义了键的类型,即string。第二个是TLogin,它是IdentityUserLogin&lt;TKey&gt;,这意味着它应该是某个类继承IdentityUserLogin,使用相同的TKey类型作为键(可能是string,也可能是int)。

同时,这些基类的内置实现如下所示:

public class IdentityUser 
    : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string> {}

其中将TKey 定义为string 用作键。其他泛型,如IdentityUserLoginIdentityUserRole,是实现基类的内置类,其中string 键。看看IdentityUserRole 长什么样子:

public class IdentityUserRole  IdentityUserRole<string> {}

看到了吗? string 也是。许多其他类使用string 作为TKey 的默认值。

所以如果你要像这样改变你的班级:

public class ApplicationUser : IdentityUser<int, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
    public virtual User user { get; set; }
}

还不行,因为我们把TKey改成了int,但是内置的IdentityUserLogin仍然使用string。所以我们需要像这样创建自己的IdentityUserLogin

public class MyNiceUserLogin : IdentityUserLogin<int>
{
}

...并像这样使用它:

public class ApplicationUser : IdentityUser<int, MyNiceUserLogin, IdentityUserRole, IdentityUserClaim>
{
    public virtual User user { get; set; }
}

...但我们仍然必须对其他类(如 IdentityUserRoleIdentityUserClaim)做同样的事情。

我将其配置为使用int。那么一对一的关系呢?

你的代码在这里:

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

    modelBuilder.Entity<ApplicationUser>()
      .HasRequired(i => i.user).WithRequiredDependent(i => i.appUser);
}

...工作正常。您正在以两种必须存在的方式进行配置,没有User 就没有ApplicationUser,反之亦然。


现在,我建议您阅读 this Stack Overflow answer 以确切了解要更改 Identity 的类以使用 int 作为键的步骤。

我也强烈推荐您阅读 John Atten 的 this post,所以您 可以深入了解如何自定义/扩展身份。

【讨论】:

  • 这是一个非常详尽且定义明确的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多