【问题标题】:Entity type 'type' is in shadow-state. A valid model requires all entity types to have corresponding CLR type实体类型“类型”处于阴影状态。一个有效的模型要求所有实体类型都有对应的 CLR 类型
【发布时间】:2017-02-01 19:17:05
【问题描述】:

我正在通过一个示例使用 Asp.net Core 和 EF 核心设置 IdentityServer4。在此过程中,我想将我的数据合同和数据访问与核心项目分开。为此,我创建了两个相关项目,一个包含 DbContext,一个包含合同。

最终我想让事情变得更复杂,但首先我只是尝试向 IdentityUser 添加一个相关对象,该对象默认为 ApplicationUser 并在涉及 Asp.net Identity 的默认项目中存储为 ApsnetUsers。

为此,我创建了一个继承 IdentityUser 的基础 ApplicationUserDto 类。我已将补充对象/表添加到该对象,并通过更新模型构建器来测试应用程序,最终,一切都按预期工作。

现在的问题。我的最终目标是两个有两个独立的类,它们都继承 ApplicationUserDto,一个用于内部用户,一个用于外部用户。每个人都有自己的补充一对一数据表。为了开始构建它,我创建了两个类,InternalUserDto 和 InternalUserProfilePropertiesDto。

ApplicationUserDto 类:

namespace SingleSignOn.Identity.DataAccess.Contracts
{
    public class ApplicationUserDto: IdentityUser {}
}

InternalUserDto.cs

namespace SingleSignOn.Identity.DataAccess.Contracts
{
    public class InternalUserDto : ApplicationUserDto
    {
        public virtual InternalUserProfilePropertiesDto InternalUserProfilePropertiesDto { get; set; }
        public InternalUserDto() { }
    }
}

InternalUserProfilePropertiesDto.cs

namespace SingleSignOn.Identity.DataAccess.Contracts.UserProperties
{
    public class InternalUserProfilePropertiesDto
    {
        public int Id { get; set; }
        public string EmployeeId { get; set; }
        public virtual InternalUserDto InternalUserDto { get; set; }
    }
}

当我尝试使用单用户身份验证的核心模板应用程序注册时使用这些类,我遇到了错误

实体类型 'SingleSignOn.Identity.DataAccess.Contracts.InternalUserDto' 在 影子状态。一个有效的模型要求所有实体类型都具有 对应的CLR类型

在模型构建器运行之后。

以下是我认为来自 DbContext 的 OnModelCreating 的相关部分:

namespace SingleSignOn.Identity.DataAccess
{

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
            modelBuilder
                  .HasAnnotation("ProductVersion", "1.0.0-rc3")
                  .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

        //Snipped

            modelBuilder.Entity("SingleSignOn.Identity.DataAccess.Contracts.ApplicationUserDto", b =>
            {
                b.Property<string>("Id");

                b.Property<int>("AccessFailedCount");

                b.Property<string>("ConcurrencyStamp")
                    .IsConcurrencyToken();

                b.Property<string>("Email")
                    .HasAnnotation("MaxLength", 256);

                b.Property<bool>("EmailConfirmed");

                b.Property<bool>("LockoutEnabled");

                b.Property<DateTimeOffset?>("LockoutEnd");

                b.Property<string>("NormalizedEmail")
                    .HasAnnotation("MaxLength", 256);

                b.Property<string>("NormalizedUserName")
                    .HasAnnotation("MaxLength", 256);

                b.Property<string>("PasswordHash");

                b.Property<string>("PhoneNumber");

                b.Property<bool>("PhoneNumberConfirmed");

                b.Property<string>("SecurityStamp");

                b.Property<bool>("TwoFactorEnabled");

                b.Property<string>("UserName")
                    .HasAnnotation("MaxLength", 256);

                b.HasKey("Id");

                b.HasIndex("NormalizedEmail")
                    .HasName("EmailIndex");

                b.HasIndex("NormalizedUserName")
                    .IsUnique()
                    .HasName("UserNameIndex");

                b.ToTable("Users");
            });

                  modelBuilder.Entity("SingleSignOn.Identity.DataAccess.Contracts.InternalUserDto", b => {
                b.ToTable("Users");
            });


            modelBuilder.Entity("SingleSignOn.Identity.DataAccess.Contracts.UserProperties.InternalUserProfilePropertiesDto", b =>
            {
                b.Property<int>("Id")
                    .ValueGeneratedOnAdd();

                b.Property<string>("EmployeeId");

                b.HasKey("Id");
            });
            modelBuilder.Entity<InternalUserDto>()
                .HasOne(typeof(InternalUserProfilePropertiesDto).ToString())
                .WithOne()
                .HasForeignKey(typeof(InternalUserProfilePropertiesDto).ToString(), "UserId")
                .IsRequired()
                .OnDelete(DeleteBehavior.Cascade);
}

我搜索了 shadow-state 并找到了检查此作为必需验证的合并请求,但我不明白为什么此类型没有 CLR 类型。仅使用 ApplicationUserDto 和配置文件属性,相同的设置工作正常,但尝试使用继承的类会立即导致错误。关于我做错了什么,影子状态是什么或为什么我的类型没有 CLR 类型的任何见解?我可以提供所需的任何其他代码或详细信息。

编辑

我似乎已经解决了我自己的问题。我在 DbContext 中没有将 InternalUserDto 或 InternalUserProfilePropertiesDto 作为 DbSet。当我添加这些并将 HasOne 更改为:

.HasOne(a => a.InternalUserProfilePropertiesDto)

现在似乎一切正常。我仍然感到困惑的是,我从来没有为原始 ApplicationUserDto 设置过 DbSet,我也从未遇到过这个问题,所以如果有人对这个主题有任何想法或建议,以及我将来如何避免这种陷阱,我仍然很感兴趣。

【问题讨论】:

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


    【解决方案1】:

    永远不要使用 DTO 作为您的数据库模型。它们用于暴露于其他层。例如,如果您正在构建一个 API,并且您想要展平您的结果。您可以使用 DTO 对象从数据库中展平您的模型。一个很棒的库是 AutoMapper。它会自动将您的模型映射到 DTO,反之亦然。

    【讨论】:

    • 这没有回答问题。此外,EF Core 模型实体您的应用程序和数据库之间的 DTO。
    猜你喜欢
    • 1970-01-01
    • 2018-10-26
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多