【问题标题】:How do I add a foreign key to Identity user in EF Core?如何在 EF Core 中向身份用户添加外键?
【发布时间】:2017-03-13 14:50:42
【问题描述】:

假设我在 EF 生成的数据库中有一个 Todo 模型和对应的 Todo 表 (DbSet<Todo>)。该表将每行存储一个待办事项。每个用户(在 ASP.NET Core Identity + IdentityServer 应用程序中)将与多个待办事项相关联(一对多,一个用户可以拥有多个待办事项)。

我这样做的方法是在 Todo 模型中添加一个 UserId 外键,该模型代表拥有待办事项的用户。

在使用 ASP.NET Core Identity 证明的类的同时,我将如何使用 EF Core 做到这一点?我的直觉是将以下内容添加到 Todo 类模型中:

public string UserId { get; set; }
[ForeignKey("UserId")]
public ApplicationUser User { get; set; }

这使用ApplicationUser(ASP.NET Core Identity 默认用户类模型)作为发现,用外键填充UserId

问题是:当我运行Update-Database 时,我得到一个错误!它说The entity type 'IdentityUserLogin<string>' requires a primary key to be defined.

浏览IdentityUserLogin 的代码,我可以看到它有一个属性UserId,应该被视为主键,对吧?

无论如何,为了确保它注册为主键,我将此代码添加到ApplicationUserOnModelCreating 方法:builder.Entity<ApplicationUser>().HasKey(u => u.Id);。我仍然得到同样的错误!不知道我在这里做错了什么:(。编辑:是的,我调用了基类,所以这不是问题。

注意:我知道我可以为每个用户添加一个包含待办事项 ID 集合而不是外键的字段,但我不确定这是否是这样做的好方法。对此问题的指导表示赞赏。

【问题讨论】:

    标签: asp.net database entity-framework asp.net-web-api asp.net-core


    【解决方案1】:

    您尚未为此共享代码,但我猜您已经在您的数据库上下文中覆盖了OnModelCreating,但没有调用base.OnModelCreating(modelBuilder);

    如果没有基本调用,您的上下文不会应用与身份相关的架构。

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Add Identity related model configuration
        base.OnModelCreating(modelBuilder);
    
        // Your fluent modeling here
    }
    

    编辑:想试一试,所以我只执行了以下任务。 TLDR 将是它为我工作。我相信您遇到的问题与您正在制作的密钥无关,并且一些不相关的东西导致您的失败,因为您遇到的失败与您正在为其构建架构的表完全不同。

    我使用 Identity 创建了一个新的 .net 核心 Web 应用程序。我做的第一件事是调用 update-database 从项目附带的初始迁移中构建数据库。这行得通。

    接下来我添加了一个 Todo 类。没有属性,只有一个 Id 和 User 字段。甚至没有标记外键。

    public class Todo
    {
        public int Id { get; set; }
        public string UserId { get; set; }
        public ApplicationUser User { get; set; }
    }
    

    我将它作为 DbSet 添加到 ApplicationDbContext 中。对上下文的唯一更改是添加 ToDo DbSet

    然后我在包管理器控制台中调用add-migration todo 来构建待办事项迁移。在 FK 就位的情况下,它按预期生成。

    public partial class Todo : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Todos",
                columns: table => new
                {
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    UserId = table.Column<string>(nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Todos", x => x.Id);
                    table.ForeignKey(
                        name: "FK_Todos_AspNetUsers_UserId",
                        column: x => x.UserId,
                        principalTable: "AspNetUsers",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Restrict);
                });
    
            migrationBuilder.CreateIndex(
                name: "IX_Todos_UserId",
                table: "Todos",
                column: "UserId");
        }
    
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Todos");
        }
    }
    

    然后,我在 About 控制器操作中添加了一些代码,以将记录粘贴到表中以确保 FK 正常工作。是的。

    public async Task<IActionResult> About()
    {
        var user = await _userManager.GetUserAsync(HttpContext.User);
        var todo = new Todo
        {
            User = user
        };
        _context.Todos.Add(todo);
        await _context.SaveChangesAsync();
    
        return View();
    }
    

    数据库中记录的屏幕截图以及表和键:

    除了你的 Todo 类中有更多字段这一显而易见的问题之外,你是否做了一些截然不同的事情,可能会导致我们遇到问题?

    【讨论】:

    • 不,我就是这样做的。事实上,覆盖已经存在于 ASP.NET Core Identity 生成的代码中,所以我只是在 base.OnModelCreating(modelBuilder); 行下方添加了我的 Fluent API。仍然出现这些错误!
    • @Biarity 人力资源管理。 AspNetUserLogins 是与 AspNetUsers 不同的表,这就是您的密钥无效的原因。一定是有什么东西妨碍了正常的表格构建。
    • 如果我什至不必使用 Fluent API,它不应该工作吗?为什么当我将它用作外键标签中的发现时,它不能只推断 ApplicationUser 的主键?也许我遗漏了一些东西(即,这是在 EF 中进行一对多的正确方法吗)?
    • FWIW,我遇到了和@Biarity 一样的问题
    • 对于 EF Core,我使用 IdentityUser 而不是 ApplicationUser
    【解决方案2】:

    戴夫,您的解决方案运行良好!

    只是给读者一些细节,将类添加到 ApplicationDbContext 作为 DbSet 意味着添加到文件 ApplicationDbContext.cs 类似的东西:

    public DbSet<MyClass> MyClass { get; set; }
    

    以及何时需要(在包管理器控制台中): PM> Add-Migration MyClass PM> 更新数据库

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-03
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-25
      • 1970-01-01
      相关资源
      最近更新 更多