【问题标题】:Manually Script ASP.Net Identity Existing Database手动编写 ASP.Net 身份现有数据库脚本
【发布时间】:2016-09-16 17:25:55
【问题描述】:

我有一个现有的数据库,其中已有一个角色表,我正在尝试让 Identity 使用表中的现有角色,但我不断收到此错误。

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

我想要实现的表映射是,

  • AspNetUsers -> 用户 (ApplicationUser)
  • AspNetRoles -> 角色 (ApplicationRole)
  • AspNetUserLogins -> 用户登录 (ApplicationUserLogin)
  • AspNetUserRoles -> RoleUser (ApplicationUserRole)

我不能使用代码优先,因为数据库正在被其他应用程序使用。所以我必须将我的脚本更改发送给 DBA。

** 现有的 SQL 表 **

/* Object:  Table [dbo].[Role] */
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Role](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NOT NULL,
    [Description] [varchar](100) NOT NULL CONSTRAINT [DF_Role_Description]  DEFAULT (''),
 CONSTRAINT [PK_Role] 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

SET ANSI_PADDING OFF
GO

/* Object:  Table [dbo].[RoleUser] */
CREATE TABLE [dbo].[RoleUser](
    [UserID] [int] NOT NULL,
    [RoleID] [int] NOT NULL,
 CONSTRAINT [PK_AppUserRole] PRIMARY KEY CLUSTERED 
(
    [UserID] ASC,
    [RoleID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]

GO

/* Object:  Table [dbo].[User] */
CREATE TABLE [dbo].[User](
    [ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
    [UserName] [dbo].[shortString] NOT NULL CONSTRAINT [DF_User_UserName]  DEFAULT (''),
    [FirstName] [dbo].[shortString] NULL CONSTRAINT [DF_User_FirstName]  DEFAULT (''),
    [LastName] [dbo].[shortString] NULL CONSTRAINT [DF_User_LastName]  DEFAULT (''),
    [Email] [dbo].[longString] NULL CONSTRAINT [DF_User_Email]  DEFAULT (''),
    [Pager] [dbo].[smallString] NULL CONSTRAINT [DF_User_Pager]  DEFAULT (''),
    [IsActive] [bit] NOT NULL CONSTRAINT [DF_User_IsActive]  DEFAULT ((1)),
    [LastPasswordChange] [datetime] NULL,
    [AccountLockedDate] [datetime] NULL,
    [AccountLockedByComputerName] [dbo].[shortString] NULL,
    [AccountLockedByUserName] [dbo].[shortString] NULL,
    [LastActive] [datetime] NULL,
    [PasswordHash] [nvarchar](max) NULL,
    [SecurityStamp] [nvarchar](max) NULL,
    [Discriminator] [nvarchar](max) NULL,
    [EmailConfirmed] [bit] NULL,
    [PhoneNumber] [nvarchar](50) NULL,
    [PhoneNumberConfirmed] [bit] NULL,
    [TwoFactorEnabled] [bit] NULL,
    [LockoutEndDateUtc] [datetime] NULL,
    [LockoutEnabled] [bit] NULL,
    [AccessFailedCount] [int] NULL,
 CONSTRAINT [PK_AppUser] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

数据库上下文

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

            // Asp.net Identity
            modelBuilder.Entity<ApplicationUser>().ToTable("User");
            modelBuilder.Entity<ApplicationRole>().ToTable("Role");
            modelBuilder.Entity<ApplicationUserClaim>().ToTable("UserClaims");
            modelBuilder.Entity<ApplicationUserLogin>().ToTable("UserLogins");
            modelBuilder.Entity<ApplicationUserRole>().ToTable("RoleUser");
        }

身份类别

public class ApplicationUserLogin : IdentityUserLogin<int> { }
    public class ApplicationUserClaim : IdentityUserClaim<int> { }
    public class ApplicationUserRole : IdentityUserRole<int> { }

    public class ApplicationRole : IdentityRole<int, ApplicationUserRole>, IRole<int>
    {
        public string Description { get; set; }

        public ApplicationRole() : base() { }
        public ApplicationRole(string name)
            : this()
        {
            this.Name = name;
        }

        public ApplicationRole(string name, string description)
            : this(name)
        {
            this.Description = description;
        }
    }

    public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Password { get; set; }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
        {
            var userIdentity = await manager
                .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            return userIdentity;
        }
    }

尝试创建 FK/PK 关系但没有成功。

【问题讨论】:

  • 你真正想做什么?您是否需要 ApplicationRole 和 Role 来共享相同的现有表?
  • ApplicationRole 只是扩展了我的 IdentityRole 以使用 int 而不是字符串。我只是想让 Identity 使用 Role 表来管理角色。

标签: c# asp.net asp.net-identity


【解决方案1】:

你需要告诉EF和IdentityRoleUserRole之间的关系。

尝试添加以下内容:

public class ApplicationUserRole : IdentityUserRole<int>
{
    public ApplicationUserRole()
        : base()
    { }
    //this is important
    public virtual ApplicationRole Role { get; set; }
}

然后在您的OnModelCreating 添加此行以设置关系:

modelBuilder.Entity<ApplicationUserRole>().HasRequired(ur => ur.Role).WithMany().HasForeignKey(ur => ur.RoleID); 

另外,如果上述方法不能解决问题,请发布您的 DbContext 代码。

【讨论】:

    【解决方案2】:

    如果我创建一个新的 ASP.NET MVC 应用程序并按照您的指示更改身份信息并创建一个仅包含您指定的表的数据库,然后我尝试登录,那么我会收到错误

    列名“密码”无效。

    这是有道理的,因为表的定义中没有“密码”字段,但该字段是在您的实体中定义的。

    然后我将OnModelCreating方法从:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    
        // Asp.net Identity
        modelBuilder.Entity<ApplicationUser>().ToTable("User");
        modelBuilder.Entity<ApplicationRole>().ToTable("Role");
        modelBuilder.Entity<ApplicationUserClaim>().ToTable("UserClaims");
        modelBuilder.Entity<ApplicationUserLogin>().ToTable("UserLogins");
        modelBuilder.Entity<ApplicationUserRole>().ToTable("RoleUser");
    }
    

    到:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    
        // Asp.net Identity
        modelBuilder.Entity<ApplicationUser>().ToTable("User");
        modelBuilder.Entity<ApplicationRole>().ToTable("Role");
        modelBuilder.Entity<ApplicationUserClaim>().ToTable("Role");
        modelBuilder.Entity<ApplicationUserLogin>().ToTable("UserLogins");
        modelBuilder.Entity<ApplicationUserRole>().ToTable("RoleUser");
    }
    

    然后我得到错误:

    实体类型 'ApplicationUserClaim' 和 ApplicationRole' 不能共享表 'Role' 因为它们不在同一类型层次结构中,或者与匹配的主键没有有效的一对一外键关系他们之间。

    注意我的错误是如何抱怨表 Role 而你的错误是抱怨表 Roles

    所以,考虑到所有这些,我有一些意见、建议和要求:

    1. 没有任何基本问题阻止您以您想要的方式使用 ASP.NET 标识,因为我能够根据您在全新安装时的要求进行设置,并克服了它抱怨实体类型共享的问题表格。
    2. 也许您的应用中有其他实体存在冲突,这可能吗?
    3. 您的数据库中是否同时拥有 Role 和 Roles 表?还是您项目中的实体?你确定这是你得到的错误,使用你发布的这个确切的代码吗?正如我所说,奇怪的是你错误地抱怨 Roles 而我抱怨 Role
    4. 您能否提供问题的最小可验证示例 (https://stackoverflow.com/help/mcve),正如我所说,我无法从干净的 MVC 项目中重现该问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-21
      相关资源
      最近更新 更多