【问题标题】:Custom database tables for Identity身份的自定义数据库表
【发布时间】:2015-12-21 16:38:20
【问题描述】:

我正在尝试为身份验证创建自定义表,但无论我尝试重新创建身份表多少次,我都会收到此错误:

实体类型“BBRoleType”和“UserRoleType”不能共享表“UserRoleTypes”,因为它们不在同一类型层次结构中,或者它们之间没有有效的一对一外键关系和匹配的主键。

这是我在数据库中的用户表:

并导出为 SQL:

/****** Object:  Table [dbo].[User]    Script Date: 21/12/2015 18:42:21 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[User](
    [Id] [uniqueidentifier] NOT NULL,
    [Email] [nvarchar](255) NOT NULL,
    [IsConfirmed] [bit] NOT NULL,
    [PasswordHash] [nvarchar](500) NULL,
    [SecurityStamp] [nvarchar](255) NULL,
    [UserName] [nvarchar](255) NOT NULL,
    [CreateDate] [datetime] NOT NULL,
    [LastOnlineDate] [datetime] NOT NULL,
    [BirthDate] [datetime] NULL,
    [FacebookAccessToken] [nvarchar](max) NOT NULL,
    [FacebookName] [nvarchar](500) NOT NULL,
    [FacebookId] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
/****** Object:  Table [dbo].[UserClaim]    Script Date: 21/12/2015 18:42:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserClaim](
    [Id] [bigint] NOT NULL,
    [UserId] [uniqueidentifier] NOT NULL,
    [ClaimValue] [nvarchar](max) NOT NULL,
    [ClaimType] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_UserClaim] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
/****** Object:  Table [dbo].[UserLogin]    Script Date: 21/12/2015 18:42:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserLogin](
    [UserId] [uniqueidentifier] NOT NULL,
    [ProviderKey] [nvarchar](max) NOT NULL,
    [LoginProvider] [nvarchar](max) NOT NULL,
    [UserLoginId] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_UserLogin] PRIMARY KEY CLUSTERED 
(
    [UserLoginId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
/****** Object:  Table [dbo].[UserRole]    Script Date: 21/12/2015 18:42:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserRole](
    [RoleId] [uniqueidentifier] NOT NULL,
    [UserId] [uniqueidentifier] NOT NULL
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[UserRoleType]    Script Date: 21/12/2015 18:42:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserRoleType](
    [Id] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_UserRoleType] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[User] ADD  CONSTRAINT [DF_User_IsConfirmed]  DEFAULT ((0)) FOR [IsConfirmed]
GO
ALTER TABLE [dbo].[UserLogin] ADD  CONSTRAINT [DF_UserLogin_UserLoginId]  DEFAULT (newid()) FOR [UserLoginId]
GO
ALTER TABLE [dbo].[UserRoleType] ADD  CONSTRAINT [DF_UserRoleType_Id]  DEFAULT (newid()) FOR [Id]
GO
ALTER TABLE [dbo].[UserClaim]  WITH CHECK ADD  CONSTRAINT [FK_UserClaim_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([Id])
GO
ALTER TABLE [dbo].[UserClaim] CHECK CONSTRAINT [FK_UserClaim_User]
GO
ALTER TABLE [dbo].[UserLogin]  WITH CHECK ADD  CONSTRAINT [FK_UserLogin_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([Id])
GO
ALTER TABLE [dbo].[UserLogin] CHECK CONSTRAINT [FK_UserLogin_User]
GO
ALTER TABLE [dbo].[UserRole]  WITH CHECK ADD  CONSTRAINT [FK_UserRole_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([Id])
GO
ALTER TABLE [dbo].[UserRole] CHECK CONSTRAINT [FK_UserRole_User]
GO
ALTER TABLE [dbo].[UserRole]  WITH CHECK ADD  CONSTRAINT [FK_UserRole_UserRoleTyp] FOREIGN KEY([RoleId])
REFERENCES [dbo].[UserRoleType] ([Id])
GO
ALTER TABLE [dbo].[UserRole] CHECK CONSTRAINT [FK_UserRole_UserRoleTyp]
GO

创建表后,我为数据库添加了一个 ADO.NET 数据实体模型。

我创建了这些类以映射到自定义标识类:

public class BBUserLogin : IdentityUserLogin<Guid> { }
public class BBUserRole : IdentityUserRole<Guid> { }

public class BBRoleType : IdentityRole<Guid,BBUserRole> { }
public class BBUserClaim : IdentityUserClaim<Guid> { }

public class BBUser : IdentityUser<Guid, BBUserLogin, BBUserRole, BBUserClaim>
{
    public DateTime CreateDate { get; set; }
    public DateTime LastOnlineDate { get; set; }
    public DateTime? BirthDate { get; set; }
    public string FacebookAccessToken { get; set; }
    public string FacebookName { get; set; }
    public string FacebookId { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<BBUser, Guid> manager)
    { 
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        userIdentity.AddClaim(new Claim(TCCustomClaimTypes.FirstName, this.FacebookName.SubstringUpToFirst(' ')));
        return userIdentity;
    }
}

然后将我的 DbContext 设置为:

public class ApplicationDbContext : IdentityDbContext<BBUser, BBRoleType, Guid, BBUserLogin, BBUserRole, BBUserClaim>
{
    public ApplicationDbContext() : base("MyIdentityConnection")
    {

    }

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

        modelBuilder.HasDefaultSchema("dbo");

        modelBuilder.Entity<BBUser>().ToTable("User");
        modelBuilder.Entity<BBUserClaim>().ToTable("UserClaim");
        modelBuilder.Entity<BBUserLogin>().ToTable("UserLogin");
        modelBuilder.Entity<BBUserRole>().ToTable("UserRole");
        modelBuilder.Entity<BBRoleType>().ToTable("UserRoleType");

        modelBuilder.Entity<BBUser>().Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<BBUserClaim>().Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<BBRoleType>().Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }

我认为我并不重要,但我尽可能使用 Guid/[uniqueidentifier] 作为 ID(使用通用 TKey 的地方)。 IdentityUserClaim 不允许更改 Id 类型,因此我为此使用 bigint。并不是说我认为这很重要:-)

我整天都在为这个问题撞墙,但我不知道我做错了什么。

【问题讨论】:

    标签: c# asp.net entity-framework asp.net-identity-2


    【解决方案1】:

    在我看来,键名 Id、Id、UserId 和 RoleId 需要正确命名。您可以在“用户”表上将键“Id”更改为“UserId”吗?删除 UserClaim 表上的 Id 键。将 UserRoleType 表上的“Id”更改为 RoleId。

    我认为这将解决您的问题。

    【讨论】:

    • 但是 Id 名称应该是正确的。用户表必须与IdentityUser 类匹配,该类指示public virtual TKey Id { get; set; } 属性,这就是我使用名称Id 的原因。如果有办法解决它,我很高兴听到它。
    • 我不认为问题出在代码上,虽然它需要修改,但问题在于数据库,您的模型没有正确的关系键控。例如,您的 User 表有一个 Id 键,然后您有另一个以 UserId 作为键的表,据说它会映射回 User.Id 但那很讨厌。使正确命名的键相同。您可以在 userId 的正确位置使用 Id,因此将 userId 作为键删除,并且不要将“Id”用作除用户以外的任何其他内容的键。
    • 我不明白 Entity Framework 是否会因为名称为 IdUserId 而自动为 id 创建引用。我已将数据库导出为 SQL 以显示密钥的设置方式(更新了问题)。
    猜你喜欢
    • 2017-06-21
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 2011-02-23
    • 2012-10-12
    • 2018-02-01
    • 1970-01-01
    • 2011-02-20
    相关资源
    最近更新 更多