当fk与pk不同时,如何链接一对一关系 - EntityFramework

时间:2017-03-06 03:21:30

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

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

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

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

ASPNETUsers表[标准列]

  • Id,[pk]
  • 用户名,
  • PasswordHash,
  • SecurityStamp,
  • Discriminator,
  • 电子邮件,
  • EmailConfirmed,
  • PhoneNumber,
  • PhoneNumberConfirmed,
  • TwoFactorEnabled,
  • LockoutEndDateUtc,
  • LockoutEnabled,
  • AccessFailedCount
  • userId [fk to users table]

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

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

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

更新 在运行它时给我错误  MySql.Data.MySqlClient.MySqlException:未知列&#39; Extent8.appUser_Id&#39;在&#39; on条款&#39;

如果我定义

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

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

ApplicationUser_Claims_Source_ApplicationUser_Claims_Target ::参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同。属性类型&#39; UserId&#39;在实体&#39; IdentityUserClaim&#39;与财产类型不匹配&#39; UserID&#39;在实体&#39; ApplicationUser&#39;在参考约束&#39; ApplicationUser_Claims&#39;。 ApplicationUser_Logins_Source_ApplicationUser_Logins_Target ::参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同。属性类型&#39; UserId&#39;在实体&#39; IdentityUserLogin&#39;与财产类型不匹配&#39; UserID&#39;在实体&#39; ApplicationUser&#39;在引用约束&#39; ApplicationUser_Logins&#39;。 ApplicationUser_Roles_Source_ApplicationUser_Roles_Target ::参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同。属性类型&#39; UserId&#39;实体&#39; IdentityUserRole&#39;与财产类型不匹配&#39; UserID&#39;在实体&#39; ApplicationUser&#39;在参考约束&#39; ApplicationUser_Roles&#39;。

1 个答案:

答案 0 :(得分:1)

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

使用一对一关系时,实体框架使用子项中父项的Id列作为父项的FK,它不会创建第二列FK,因为那将被视为一对多关系,因为第二列将允许父{4}存在于许多子条目中,而PK作为FK则不会。< / p>

我应该如何配置两个键?

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

但是,这不是世界末日。 Identity的内置实现使用integer作为其类的键( AspNetUsers,AspNetRoles等...... ),但它们允许我们使用其他类型的主键。

所以...我该怎么办?

Identity为每个表定义了两个类,因此有两个string类,两个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<TKey>的类,使用与密钥相同的IdentityUserLogin类型(也许TKey },也许是string)。

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

int

public class IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string> {} 定义为TKey以用作关键字。其他泛型,如stringIdentityUserLogin,是内置类,实现了IdentityUserRole键的基类。看看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; } } IdentityUserRole等其他类做同样的事情。

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

您的代码在这里:

int

......工作正常。您的配置方式是必须,没有protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<ApplicationUser>() .HasRequired(i => i.user).WithRequiredDependent(i => i.appUser); } 没有ApplicationUser,反之亦然。

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

  

强烈建议您阅读John Atten的this post,所以   可以深入了解如何定制/扩展身份。