【问题标题】:EntityType ''IdentityUserRole' has no key defined errorEntityType ''IdentityUserRole' 没有键定义错误
【发布时间】:2017-02-19 22:47:41
【问题描述】:

首先使用实体​​框架代码。

尝试使用 IdentityRole id 作为自定义类的外键。

关系是正确的,但是当我尝试将数据添加到我的自定义表时,我得到了这个错误。

EntityType 'IdentityUserRole' 没有定义键。定义键 此实体类型。 IdentityUserRoles:EntityType:EntitySet 'IdentityUserRoles' 基于类型 'IdentityUserRole' 没有 已定义键。

代码:

自定义表/类

public class UserRoleAccess
{
    [Key]
    public long UserRoleAccessId { get; set; }

    public string UserRoleId { get; set; }

    public virtual ApplicationRole ApplicationRole { get; set; }

    public bool IsActive { get; set; }

    public string Name { get; set; }

    public int UserRoleAccessType { get; set; }
}

身份角色

public class ApplicationRole : IdentityRole
{
    public virtual ICollection<UserRoleAccess> UserRoleAccess { get; set; }
}

绑定

    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();


        modelBuilder.Entity<IdentityUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId");
        modelBuilder.Entity<ApplicationUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId");
        modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
        modelBuilder.Entity<IdentityRole>().ToTable("Roles");
        modelBuilder.Entity<ApplicationRole>().ToTable("Roles");
        modelBuilder.Entity<UserRoleAccess>().ToTable("UserRoleAccess");

        modelBuilder.Entity<ApplicationUser>().HasRequired(p => p.Person)
            .WithMany(b => b.Users);

        modelBuilder.Entity<ApplicationUser>().HasRequired(p => p.Person)
            .WithMany(b => b.Users)
            .HasForeignKey(p => p.PersonId);

        modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
        modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
        modelBuilder.Entity<ApplicationRole>().HasKey<string>(r => r.Id);
        modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });


    }

数据库中的关系(正确):

尝试创建一个 id 属性并设置一个 [Key] 属性,但没有成功:

public class ApplicationRole : IdentityRole
{
    [Key]
    public string Id { get; set; }

    public virtual ICollection<UserRoleAccess> UserRoleAccess { get; set; }
}

添加数据时运行此代码:

    public static void CreateUserRoleAccess(string name, int type, string id)
    {

        using (var context = new UserRoleAccessContext())
        {
            var userRoleAccess = new UserRoleAccess();

            userRoleAccess.ApplicationRole = new ApplicationRole { Id = id };

            userRoleAccess.UserRoleId = id;
            userRoleAccess.IsActive = true;

            userRoleAccess.UserRoleAccessType = type;

            userRoleAccess.Name = name;

            context.UserRoleAccess.Add(userRoleAccess);

            context.SaveChanges();
        }
    }

我错过了什么?

编辑:

IdentityRole 类:

IdentityRole

【问题讨论】:

  • 我们不会在 ObjectType 之前使用 new 关键字,是吗?公共新字符串 ID { 获取;放; }
  • @Waleed 重新添加了一些东西。你的评论有什么帮助?属性前加或不加new关键字还是不行
  • 你能发布 IdentityRole 类吗?您在模型构建器中有一个到 IdentityRole 键的映射
  • @matthijsb 它是内置的 Ef 类:msdn.microsoft.com/en-us/library/dn613249(v=vs.108).aspx
  • 错误消息指出错误是关于实体 IdentityUserRole,而不是关于 IdentityRole。您的映射未定义此实体与其他实体之间的关系,因此 EF 可能正在为该实体隐式创建关系。 PK 是否在“UserRoles”表中的数据库中生成?能否展示实体 IdentityUserRole 的代码?

标签: c# entity-framework asp.net-mvc-5 ef-code-first


【解决方案1】:

所以,您正在使用 MVC 5ASP.NET Identity 2.0。我猜你的项目有 Microsoft.AspNet.Identity.EntityFramework 的 Nuget 包,并且已经在你的数据库中创建了正确的表。

也许您的问题是因为您正在重新定义标准身份表的映射。你真的需要明确地映射表名和键吗?我会尝试保留原始映射,并且只为您的自定义实体和字段添加显式映射。 我认为您不需要 ToTable 映射,因为基本实体在其代码中的某处有一个映射,并且您的实体扩展了它们。

几个问题:

  • UserRoleAccess.UserRoleId 是什么意思?它是用户 ID 还是角色 ID?如果它打算包含 UserRole id,它是一个组合键,而不是单个值,因此 String 属性不太可能这样做。也许你应该重命名它。

  • 你想在方法CreateUserRoleAccess中具体做什么:为已经存在并且已经相关的角色和用户添加一个新的UserRoleAccess(即UserRole关系已经存在) ?或者为已经存在但不相关的用户和角色添加新的UserRoleUserRoleAccess?我假设您此时不想创建角色或用户,它们已经存在,我错了吗?

  • 无论如何,在您的 CreateUserRoleAccess 方法中,在这一行:

    userRoleAccess.ApplicationRole = new ApplicationRole { Id = id };
    

    除非您在同一时刻创建新角色,否则您应该执行Find 或其他 Linq 查询并从上下文中获取现有角色。也许只是改变它会使你的代码工作:

    //userRoleAccess.ApplicationRole = new ApplicationRole { Id = id };
    userRoleAccess.ApplicationRole = context.Roles.Find(id) as ApplicationRole;
    

我创建了一个 MVC 项目并尝试了您的代码,并进行了几处更改:

我没有包含任何显式的 EF 绑定或映射,只是为了尝试使用原始身份模型并查看它是否有效。

我扩展了 Identity DbContext,只是为 UserRoleAccess 添加了一个 DbSet:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public virtual IDbSet<UserRoleAccess> UserRoleAccesses { get; set; }

    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}  

在添加您的自定义实体 ApplicationRole 和 UserRoleAccess、生成迁移并更新数据库后,我得到了与您相同的 UserRoleAccess 表,但在 Roles 表中还有一个新列 Discriminator:

这意味着当您使用 ApplicationRole 实体扩展 IdentityRole 实体时,EF 正在使用 TPH(按层次结构表)。他们共享桌子。这是隐式的,不需要编写绑定(实际上,不需要的显式绑定往往会干扰)。

因此,如果您的角色表缺少此字段,这可能是您出错的原因。

我运行 MVC Web,并在页眉中使用注册链接创建了一个新用户。我运行以下代码(通过将其添加到索引控制器),它工作:

    public void CreateUserRoleAccess(string name, int type, string id)
    {
        //Insert role (run only once)
        using (var context = new ApplicationDbContext())
        {
            var role = new ApplicationRole { Id = id, Name = "Role1" };
            var user = context.Users.FirstOrDefault<ApplicationUser>();
            //user.Roles.Add(role);
            role.Users.Add(new IdentityUserRole { RoleId = role.Id, UserId = user.Id });

            context.Roles.Add(role);
            context.SaveChanges();
        }

        using (var context = new ApplicationDbContext())
        {
            var userRoleAccess = new UserRoleAccess();

            //userRoleAccess.ApplicationRole = new ApplicationRole { Id = id };
            userRoleAccess.ApplicationRole = context.Roles.Find(id) as ApplicationRole;

            //Is this a userId or a roleId? Does not seem OK to assign id param here
            userRoleAccess.UserRoleId = id;
            userRoleAccess.IsActive = true;

            userRoleAccess.UserRoleAccessType = type;

            userRoleAccess.Name = name;

            context.UserRoleAccesses.Add(userRoleAccess);

            context.SaveChanges();
        }
    }

请注意,我首先创建了一个具有不同上下文范围的新角色,以确保当我获得有趣的代码时该角色存在。我稍后会使用该角色从上下文中获取它。

希望这会有所帮助。如果您愿意,我可以将整个解决方案代码发送给您。

编辑 - UserRoleAccess 表:

        CreateTable(
            "dbo.UserRoleAccesses",
            c => new
                {
                    UserRoleAccessId = c.Long(nullable: false, identity: true),
                    UserRoleId = c.String(),
                    IsActive = c.Boolean(nullable: false),
                    Name = c.String(),
                    UserRoleAccessType = c.Int(nullable: false),
                    ApplicationRole_Id = c.String(maxLength: 128),
                })
            .PrimaryKey(t => t.UserRoleAccessId)
            .ForeignKey("dbo.AspNetRoles", t => t.ApplicationRole_Id)
            .Index(t => t.ApplicationRole_Id);

有用的链接:

Introduction to ASP.NET Identity - 我使用此信息创建了简单的 MVC 解决方案。

ASP.NET Identity, extract from book Pro ASP.NET MVC 5

【讨论】:

  • 为努力投票!谢谢!虽然我不确定你是否完全理解我想要做什么。您能否展示一下您的 UserRoleAccess 表的外观?在我看来,您有来自 AspNetUsers 表和 AspnetRole 表的外键。我只希望从 aspNetRoles 表中获得一个关键属性。在 CreateUserRoleAccess 方法中,id 赋予我们一个已经存在的角色的 id。我会尝试按照您的建议查找 id。
  • 不客气!我将 UserRoleAccess 表添加到答案中。 AspNetRoles 表有一个外键,而不是 AspNetUsers 表。
  • 那么你想要的是使用属性 UserRoleId 作为外键字段和 ApplicationRole 作为导航属性?您可以使用 ForeignKey 属性执行此操作,如下所示:[ForeignKey("UserRoleId")] public virtual ApplicationRole ApplicationRole { get; set; }。您可以将属性放在 ApplicationRole 属性或 UserRoleId 属性中,只是参数必须是另一个属性名称。
  • 如果您这样做,ApplicationRole_Id 字段将不再自动生成(因为 UserRoleId 字段将在外键中使用)。为了清楚起见,我建议将 UserRoleId 的名称更改为 ApplicationRoleId。
  • 如果您更喜欢流畅的映射而不是注释,您可以在 OnModelCreating 方法中使用以下代码来代替:modelBuilder.Entity&lt;UserRoleAccess&gt;().HasRequired(ura =&gt; ura.ApplicationRole) .WithMany().HasForeignKey(ura =&gt; ura.UserRoleId);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-11
  • 2016-04-02
  • 2016-03-16
  • 2013-08-04
相关资源
最近更新 更多