【发布时间】:2018-10-26 06:20:53
【问题描述】:
我一直在玩这个quickstart example 并且一直在尝试看看我可以自定义数据库到什么程度(我有一个现有的数据库,我一直在尝试复制一半)。
我已经成功触发了下面的异常,但无法修复它,部分原因是我不明白消息告诉我什么。
InvalidOperationException:实体类型 'Microsoft.AspNetCore.Identity.IdentityRole' 处于阴影状态。一种 有效的模型要求所有实体类型都有对应的 CLR 类型。
我的ApplicationDbContext如下:
using IdentityServerWithAspIdAndEF.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
namespace IdentityServerWithAspIdAndEF.Data
{
public class ApplicationDbContext : IdentityDbContext<User, Role, int>
{
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> Options
) : base(Options) { }
protected override void OnModelCreating(ModelBuilder ModelBuilder)
{
base.OnModelCreating(ModelBuilder);
// Customisations
// "IdentityServer4AspNetIdentity.Models.ApplicationUser"
ModelBuilder.Entity<User>(B =>
{
B.Property<int>(P => P.Id)
.HasColumnName("AccountId")
.ValueGeneratedOnAdd();
B.Property<string>("ConcurrencyStamp")
.HasMaxLength(512)
.IsConcurrencyToken();
B.Property<string>("Email")
.HasMaxLength(512)
.IsRequired();
B.Property<bool>("EmailConfirmed")
.ValueGeneratedOnAdd();
B.Property<string>("NormalisedEmail")
.HasMaxLength(512)
.IsRequired();
B.Property<string>("NormalisedUserName")
.HasMaxLength(256)
.IsRequired();
B.Property<string>("PasswordHash");
B.Property<string>("SecurityStamp")
.IsRequired();
B.Property<bool>("TwoFactorEnabled")
.ValueGeneratedOnAdd();
B.Property<string>("UserName")
.HasMaxLength(256)
.IsRequired();
B.Property<DateTime>("Registered")
.ValueGeneratedOnAdd();
B.Property<DateTime>("LastVisit")
.IsRequired();
B.HasKey("AccountId");
B.HasIndex("NormalisedEmail")
.HasName("IX_Users_NormalisedEmail");
B.HasIndex("NormalisedUserName")
.IsUnique()
.HasName("IX_Users_NormalisedUserName");
B.ToTable("Users");
});
// "Microsoft.AspNetCore.Identity.IdentityRole"
ModelBuilder.Entity<Role>(B =>
{
B.Property<int>(P => P.Id)
.HasColumnName("RoleId")
.ValueGeneratedOnAdd();
B.Property<string>("ConcurrencyStamp")
.HasMaxLength(512)
.IsConcurrencyToken();
B.Property<string>("Name")
.HasMaxLength(256);
B.Property<string>("NormalisedName")
.HasMaxLength(256);
B.HasKey(P => P.Id);
B.HasIndex("NormalisedName")
.IsUnique()
.HasName("IX_Roles_NormalisedName");
B.ToTable("Roles");
});
// "Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>"
ModelBuilder.Entity<RoleClaim>(B =>
{
B.Property<int>(P => P.Id)
.HasColumnName("ClaimId")
.ValueGeneratedOnAdd();
B.Property<string>("ClaimType")
.HasMaxLength(128);
B.Property<string>("ClaimValue")
.HasMaxLength(128);
B.Property<int>("RoleId")
.IsRequired();
B.HasIndex(P => P.RoleId)
.HasName("IX_RoleClaims_RoleId");
B.HasOne(D => D.Claim)
.WithMany()
.HasForeignKey(P => P.RoleId)
.OnDelete(DeleteBehavior.Cascade);
B.ToTable("RoleClaims");
});
// "Microsoft.AspNetCore.Identity.IdentityUserClaim<string>"
ModelBuilder.Entity<UserClaim>(B =>
{
B.Property<int>(P => P.Id)
.HasColumnName("ClaimId")
.ValueGeneratedOnAdd();
B.Property<string>("ClaimType")
.HasMaxLength(128);
B.Property<string>("ClaimValue")
.HasMaxLength(128);
B.Property<int>(P => P.UserId)
.HasColumnName("AccountId")
.IsRequired();
B.HasIndex("AccountId")
.HasName("IX_UserClaims_AccountId");
B.HasOne(D => D.Account)
.WithMany()
.HasForeignKey(P => P.AccountId)
.OnDelete(DeleteBehavior.Cascade);
B.ToTable("UserClaims");
});
// "Microsoft.AspNetCore.Identity.IdentityUserLogin<string>"
ModelBuilder.Entity<Login>(B =>
{
B.Property<int>(P => P.UserId)
.HasColumnName("LoginId")
.ValueGeneratedOnAdd();
B.Property<string>("LoginProvider")
.HasMaxLength(450)
.IsRequired();
B.Property<string>("ProviderKey")
.HasMaxLength(450)
.IsRequired();
B.Property<string>("ProviderDisplayName");
B.Property<int>("AccountId")
.IsRequired();
B.HasIndex("LoginProvider")
.HasName("IX_Logins_LoginProvider");
B.HasIndex("ProviderKey")
.HasName("IX_Logins_ProviderKey");
B.HasIndex("AccountId")
.HasName("IX_Logins_AccountId");
B.HasOne(D => D.Account)
.WithMany()
.HasForeignKey(P => P.AccountId)
.OnDelete(DeleteBehavior.Cascade);
B.ToTable("Logins");
});
// "Microsoft.AspNetCore.Identity.IdentityUserRole<string>"
ModelBuilder.Entity<UserRole>(B =>
{
B.Property<int>(P => P.UserId)
.HasColumnName("AccountId")
.IsRequired();
B.Property<int>("RoleId")
.IsRequired();
B.HasIndex("AccountId")
.HasName("IX_RoleMap_AccountId");
B.HasIndex("RoleId")
.HasName("IX_RoleMap_RoleId");
B.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
B.HasOne(P => P.Account)
.WithMany()
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade);
B.ToTable("RoleMap");
});
// "Microsoft.AspNetCore.Identity.IdentityUserToken<string>"
ModelBuilder.Entity<Token>(B =>
{
B.Property<int>(P => P.UserId)
.HasColumnName("AccountId")
.IsRequired();
B.Property<string>("LoginProvider")
.HasMaxLength(128)
.IsRequired();
B.Property<string>("Name")
.HasMaxLength(64);
B.Property<string>("Value");
B.HasOne(P => P.Account)
.WithMany()
.HasForeignKey(P => P.AccountId)
.OnDelete(DeleteBehavior.Cascade);
B.ToTable("UserTokens");
});
// Non-identity extras
/* snipped */
}
}
}
与这些 DbSet 对应的实体如下:
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
namespace IdentityServerWithAspIdAndEF.Models
{
public class User : IdentityUser<int>
{
public int AccountId
{
get => base.Id;
set => base.Id = value;
}
public string NormalisedEmail
{
get => base.NormalizedEmail;
set => base.NormalizedEmail = value;
}
public string NormalisedUserName
{
get => base.NormalizedUserName;
set => base.NormalizedUserName = value;
}
public DateTime Registered { get; set; }
public DateTime LastVisit { get; set; }
public AccountDetail UserDetails { get; set; }
public AccountLockout Lockout { get; set; }
public PasswordReset PasswordResetRequested { get; set; }
public Concierge ConciergeAccountFlag { get; set; }
public NotValidated AccountValidatation { get; set; }
public ICollection<UserRole> AssignedRoles { get; set; }
public ICollection<UserClaim> ClaimsCollection { get; set; }
public ICollection<Login> Logins { get; set; }
public ICollection<LoginAttempt> LoginAttempts { get; set; }
public ICollection<Token> TokenCollection { get; set; }
public new int Id => throw new NotImplementedException();
public override string NormalizedEmail => throw new NotImplementedException();
public override string NormalizedUserName => throw new NotImplementedException();
}
public class Role : IdentityRole<int>
{
public int RoleId
{
get => base.Id;
set => base.Id = value;
}
public string NormalisedName
{
get => base.NormalizedName;
set => base.NormalizedName = value;
}
public ICollection<RoleClaim> ClaimsCollection { get; set; }
private new int Id => throw new NotImplementedException();
private new int NormalizedName => throw new NotImplementedException();
}
public class RoleClaim : IdentityRoleClaim<int>
{
public int ClaimId
{
get => base.Id;
set => base.Id = value;
}
public Role Claim { get; set; }
private new int Id => throw new NotImplementedException();
}
public class UserClaim : IdentityUserClaim<int>
{
public int ClaimId
{
get => base.Id;
set => base.Id = value;
}
public int AccountId
{
get => base.UserId;
set => base.UserId = value;
}
public User Account { get; set; }
private new int Id => throw new NotImplementedException();
private new int UserId => throw new NotImplementedException();
}
public class Login : IdentityUserLogin<int>
{
public int AccountId
{
get => base.UserId;
set => base.UserId = value;
}
public User Account { get; set; }
private new int UserId => throw new NotImplementedException();
}
public class UserRole : IdentityUserRole<int>
{
public int AccountId
{
get => base.UserId;
set => base.UserId = value;
}
public User Account { get; set; }
private new int UserId => throw new NotImplementedException();
}
public class Token : IdentityUserToken<int>
{
public int AccountId
{
get => base.UserId;
set => base.UserId = value;
}
private new int UserId => throw new NotImplementedException();
public User Account { get; set; }
}
}
我已阅读帖子"What does it mean for an entity type to be in “shadow state”?" 和"Entity type 'type' is in shadow-state. A valid model requires all entity types to have corresponding CLR type"
从documentation 判断,我认为我可能在某处错过或错误引用了Role 实体,但我不清楚在哪里。
提前致谢!
编辑:
重新阅读影子属性文档,“按照惯例,影子属性仅在发现关系但在依赖实体类中找不到外键属性时才创建。在这种情况下,影子外部将引入 key 属性。" 似乎支持我已经搞砸了实体。
我已尝试通过将 Role 和 RoleClaim 模型构建器实体声明中的所有属性引用更改为表达式来排除属性名称不匹配,以查看硬引用是否有帮助:
// "Microsoft.AspNetCore.Identity.IdentityRole"
ModelBuilder.Entity<Role>(B =>
{
B.Property(P => P.RoleId)
.ValueGeneratedOnAdd();
B.Property(E => E.ConcurrencyStamp)
.HasMaxLength(512)
.IsConcurrencyToken();
B.Property(E => E.Name)
.HasMaxLength(256);
B.Property(E => E.NormalisedName)
.HasMaxLength(256);
B.HasKey(P => P.Id);
B.HasIndex(E => E.NormalisedName)
.IsUnique()
.HasName("IX_Roles_NormalisedName");
B.ToTable("Roles");
});
// "Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>"
ModelBuilder.Entity<RoleClaim>(B =>
{
B.Property(P => P.ClaimId)
.ValueGeneratedOnAdd();
B.Property(E => E.ClaimType)
.HasMaxLength(128);
B.Property(E => E.ClaimValue)
.HasMaxLength(128);
B.Property(E => E.RoleId)
.IsRequired();
B.HasIndex(P => P.RoleId)
.HasName("IX_RoleClaims_RoleId");
B.HasOne(D => D.Claim)
.WithMany()
.HasForeignKey(P => P.RoleId)
.OnDelete(DeleteBehavior.Cascade);
B.ToTable("RoleClaims");
});
但到目前为止还没有运气。
【问题讨论】:
-
您为什么将所有这些
DbSets 添加到您的上下文中?它们已经存在,因为您继承自IdentityDbContext -
你说的很对,我正在测试并将它们留在里面,因为它们对运行项目没有负面或有益的影响。我已删除它们并将它们从主帖中弹出。
标签: c# entity-framework-core asp.net-core-2.0 identityserver4