【问题标题】:AspNetIdentity framework Code first ApproachAspNetIdentity 框架代码优先方法
【发布时间】:2015-04-15 18:43:56
【问题描述】:

我是 EF6 上的代码优先方法的新手。所以请见谅

我正在尝试为我的本地项目实施 AspNetIdentityframework。

我在数据库中拥有所有开箱即用的表。我保持与模型类结构相同。我没有角色只有 1 个角色。

这是我的 DbContext 类。

 public class AuthDbContext : IdentityDbContext<IdentityUser>
    {
        public AuthDbContext()
            : base("AuthDbContext")
        {
            Database.SetInitializer<AuthDbContext>(null);
        }
        public virtual DbSet<AspNetRole> AspNetRoles { get; set; }
        public virtual DbSet<AspNetUserClaim> AspNetUserClaims { get; set; }
        public virtual DbSet<AspNetUserLogin> AspNetUserLogins { get; set; }
        public virtual DbSet<AspNetUser> AspNetUsers { get; set; }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(t => t.UserId);
            modelBuilder.Entity<IdentityRole>().HasKey<string>(t => t.Id);
            modelBuilder.Entity<IdentityUser>().HasKey<string>(t => t.Id);
            modelBuilder.Entity<IdentityUserRole>().HasKey(t => new { t.RoleId,t.UserId});

            modelBuilder.Ignore<IdentityUserRole>();
            modelBuilder.Ignore<AspNetRole>();
}

我在表中有 2 个用户。我正在努力寻找一个。 我收到错误 Invalid Column Name 'Discriminator' 我在生成模型时做错了什么? 我尝试了很多选项我无法解决这个问题

这里是userManager.FindByName方法生成的sql

 exec sp_executesql N'SELECT 
        [Limit1].[C1] AS [C1], 
        [Limit1].[Id] AS [Id], 
        [Limit1].[Email] AS [Email], 
        [Limit1].[EmailConfirmed] AS [EmailConfirmed], 
        [Limit1].[PasswordHash] AS [PasswordHash], 
        [Limit1].[SecurityStamp] AS [SecurityStamp], 
        [Limit1].[PhoneNumber] AS [PhoneNumber], 
        [Limit1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed], 
        [Limit1].[TwoFactorEnabled] AS [TwoFactorEnabled], 
        [Limit1].[LockoutEndDateUtc] AS [LockoutEndDateUtc], 
        [Limit1].[LockoutEnabled] AS [LockoutEnabled], 
        [Limit1].[AccessFailedCount] AS [AccessFailedCount], 
        [Limit1].[UserName] AS [UserName]
        FROM ( SELECT TOP (1) 
            [Extent1].[Id] AS [Id], 
            [Extent1].[Email] AS [Email], 
            [Extent1].[EmailConfirmed] AS [EmailConfirmed], 
            [Extent1].[PasswordHash] AS [PasswordHash], 
            [Extent1].[SecurityStamp] AS [SecurityStamp], 
            [Extent1].[PhoneNumber] AS [PhoneNumber], 
            [Extent1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed], 
            [Extent1].[TwoFactorEnabled] AS [TwoFactorEnabled], 
            [Extent1].[LockoutEndDateUtc] AS [LockoutEndDateUtc], 
            [Extent1].[LockoutEnabled] AS [LockoutEnabled], 
            [Extent1].[AccessFailedCount] AS [AccessFailedCount], 
            [Extent1].[UserName] AS [UserName], 
            ''0X0X'' AS [C1]
            FROM [dbo].[AspNetUsers] AS [Extent1]
 WHERE ([Extent1].[Discriminator] = N''User'') //Error here ?????????
AND (((UPPER([Extent1].[UserName])) = (UPPER(@p__linq__0))) OR ((UPPER([Extent1].[UserName]) IS NULL) AND (UPPER(@p__linq__0) IS NULL)))
        )  AS [Limit1]',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'testUser'

【问题讨论】:

    标签: entity-framework-6 asp.net-identity code-first


    【解决方案1】:

    您可以在 Asp.NET Identity 2.0 的源代码中看到 hereIdentityDbContext&lt;T&gt; 已经 在OnModelCreating 中定义DbModelBuilder 配置和 DbSet&lt;AspNetRole&gt;, DbSet&lt;AspNetUserClaim&gt;, DbSet&lt;AspNetUserLogin&gt;, DbSet&lt;AspNetUser&gt;,因此您不必定义所有这些属性,也不必覆盖OnModelCreating

    你的上下文应该是这样的:

    public class AuthDbContext : IdentityDbContext<IdentityUser>
    {
        public AuthDbContext() : base("AuthDbContext")
        {
            Database.SetInitializer<AuthDbContext>(null);
        }
    }
    

    您正在定义一个DbSet&lt;AspNetUser&gt;,并且您的上下文继承自Identity&lt;IdentityUser&gt;,因此有2 个DbSets,其中一个TIdentityUser,另一个TAspNetUserIdentityUser 继承自 AspNetUser,因此 EntityFramework 通过添加名为 Discriminator 的列来管理继承。

    编辑:

    这是您要继承的类的实现。

    /// <summary>
    /// DbContext which uses a custom user entity with a string primary key
    /// </summary>
    /// <typeparam name="TUser"></typeparam>
    public class IdentityDbContext<TUser> 
            : IdentityDbContext<
                TUser, 
                IdentityRole, 
                string, 
                IdentityUserLogin,
                IdentityUserRole,
                IdentityUserClaim> 
            where TUser : IdentityUser 
    {
        /// <summary>
        /// Default constructor which uses the DefaultConnection
        /// </summary>
        public IdentityDbContext()
            : this("DefaultConnection") 
        { }
    
        /// <summary>
        /// Constructor which takes the connection string to use
        /// </summary>
        /// <param name="nameOrConnectionString"></param>
        public IdentityDbContext(string nameOrConnectionString)
            : base(nameOrConnectionString) 
        { }
    }
    

    如您所见,IdentityDbContext&lt;TUser&gt; 类继承自 IdentityDbContext&lt;TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim&gt;。后者已经定义了 IDbSet&lt;TRole&gt;IDbSet&lt;TUser&gt; 类型的属性,并且已经实现了 OnModelCreating 在我看来满足您的需求。

    /// <summary>
    /// Maps table names, and sets up relationships between the various user entities
    /// </summary>
    /// <param name="modelBuilder"></param>
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        if (modelBuilder == null)
        {
            throw new ArgumentNullException("modelBuilder");
        }
    
        // Needed to ensure subclasses share the same table
        var user = modelBuilder.Entity<TUser>().ToTable("AspNetUsers");
        user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
        user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
        user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
        user.Property(u => u.UserName).IsRequired();
    
        // CONSIDER: u.Email is Required if set on options?
    
        // Look into IValidatable...
    
        // Try this (Configure Join table name HasMany.WithMany.Map(To match 1.0 tables)
        modelBuilder.Entity<TUserRole>()
            .HasKey(r => new { r.UserId, r.RoleId })
            .ToTable("AspNetUserRoles");
    
        modelBuilder.Entity<TUserLogin>()
            .HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId })
            .ToTable("AspNetUserLogins");
    
        modelBuilder.Entity<TUserClaim>()
            .ToTable("AspNetUserClaims");
    
        var role = modelBuilder.Entity<TRole>().ToTable("AspNetRoles");
        role.Property(r => r.Name).IsRequired();
        role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
    }
    

    如果您想使用自己的AspNetRoleAspNetUserClaimAspNetUserLogin,您应该从IdentityDbContext&lt;TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim&gt; 继承并传递您的自定义实体,或者如果您想真正控制您的数据库,您应该简单地从 DbContext 继承并自己完成所有设置(您已经在做的事情)。

    我希望我很清楚,如果您有任何疑问,请不要犹豫发表评论。

    【讨论】:

    • 这给了我一个小费。我也必须进行其他更改。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-14
    • 2011-05-09
    • 2017-05-17
    相关资源
    最近更新 更多