当 fk 与 pk 不同时如何 link 一对一关系 - EntityFramework

How to link one-to-one relationship when fk is different from pk - EntityFramework

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

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

ASPNETUsers Table [标准列]

我在ApplicationUser里面添加了属性 class

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

我还需要做什么,是否正确? entityframework 如何使用这个?

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

更新 在 运行 上它给我错误 MySql.Data.MySqlClient.MySqlException:'on clause'

中的未知列 'Extent8.appUser_Id'

如果我定义

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

OnModelCreating 中,然后它尝试 link AspNetRoles 和 Claims 等 table 通过此 UserID,当然会崩溃。

ApplicationUser_Claims_Source_ApplicationUser_Claims_Target: : 引用约束的从属角色中所有属性的类型必须与主体角色中相应的 属性 类型相同。实体 'IdentityUserClaim' 上 属性 'UserId' 的类型与引用约束 [=93] 中实体 'ApplicationUser' 上 属性 'UserID' 的类型不匹配=]. ApplicationUser_Logins_Source_ApplicationUser_Logins_Target: : 引用约束的从属角色中所有属性的类型必须与主体角色中相应的 属性 类型相同。实体 'IdentityUserLogin' 上 属性 'UserId' 的类型与引用约束 [=98] 中实体 'ApplicationUser' 上 属性 'UserID' 的类型不匹配=]. ApplicationUser_Roles_Source_ApplicationUser_Roles_Target: : 引用约束的从属角色中所有属性的类型必须与主体角色中相应的 属性 类型相同。实体 'IdentityUserRole' 上 属性 'UserId' 的类型与引用约束 [=103] 中实体 'ApplicationUser' 上 属性 'UserID' 的类型不匹配=].

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

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

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

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

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

那么...我该怎么办?

Identity为每个table定义了两个class,所以有两个IdentityUser class,两个IdentityRole,依此类推。一个是基本泛型 class,它接受一些 泛型 。另一个是该基础 class 的 内置实现 ,它提供那些通用类型。

这个基地class看起来像这样:

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<TKey>,这意味着它应该是一些 class 继承 IdentityUserLogin 使用相同的 TKey 类型用作键(也许string,也许是 int).

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

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

TKey 定义为要用作键的 string。其他泛型,如 IdentityUserLoginIdentityUserRole,是内置的 classes 实现基础 classes,其中一个 string 键。看看 IdentityUserRole 长什么样:

public class IdentityUserRole  IdentityUserRole<string> {}

看到了吗? string 还有。许多其他 classes 使用 string 作为 TKey 的默认值。

因此,如果您要像这样更改 class:

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

...但我们仍然必须对其他 class 执行相同的操作,例如 IdentityUserRoleIdentityUserClaim

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

您的代码:

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

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

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


现在,我建议您阅读 以准确了解要将身份的 class 更改为使用 int 作为密钥应遵循的步骤。

I also strongly recommend you to read this post by John Atten, so you can understand deeply about how to customize/extend Identity.