如何在EF Core中向Identity用户添加外键?

时间:2016-12-22 02:09:47

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

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

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

在使用ASP.NET核心标识证明的类时,如何使用EF Core?我的直觉是将以下内容添加到Todo类模型中:

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

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

问题在于:当我运行Update-Database时出现错误!它说The entity type 'IdentityUserLogin<string>' requires a primary key to be defined.

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

无论如何,为了确保将其注册为主键,我将此代码添加到ApplicationUser的{​​{1}}方法:OnModelCreating。我仍然得到同样的错误!不知道我在这里做错了什么:(。编辑:是的,我打电话给基类,这不是问题。

注意:我知道我可以为每个带有todo项目ID集合的用户添加一个字段而不是外键,但我不确定这是否是这样做的好方法。关于这个问题的指导意见表示赞赏。

2 个答案:

答案 0 :(得分:9)

您尚未共享此代码,但我猜您已在db上下文中覆盖了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和用户字段。甚至没有标记外键。

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来构建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();
}

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

除了显而易见的是你的Todo课程中有更多的字段,你有什么不同之处可能会导致我们遇到问题吗?

答案 1 :(得分:3)

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

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

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

并在需要时(在包管理器控制台中): PM&GT;添加迁移MyClass PM&GT;更新数据库