如何在EF Core中向身份用户添加外键? [英] How do I add a foreign key to Identity user in EF Core?

查看:347
本文介绍了如何在EF Core中向身份用户添加外键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个Todo模型,并且在EF生成的数据库中有一个相应的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集合的用户添加一个字段,而不是使用外键,但是我不确定这是否是一个好方法.对此问题的指导表示赞赏.

解决方案

您尚未共享此代码,但是我想您已经在数据库上下文中覆盖了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来构建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类上有更多字段之外,您所做的其他操作是否与您完全不同,还可能导致我们遇到问题?

Let's say I have a Todo model with a corresponding Todo table (DbSet<Todo>) in an EF-generated database. The table will store a todo item per row. Each user (in an ASP.NET Core Identity + IdentityServer app) will be associated with multiple todo items (one-to-many, a user can have multiple todo items).

The way I'd do it is to add a UserId foreign key to the Todo model that represents the user that owns the todo item .

How would I do that with EF Core while utilizing the classes proved by ASP.NET Core Identity? My intuition was to add the following to the Todo class model:

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

This uses ApplicationUser (the ASP.NET Core Identity default user class model) as discovery to populate UserId with a foreign key.

Here's the problem: when I run Update-Database I get an error! It says The entity type 'IdentityUserLogin<string>' requires a primary key to be defined..

Browsing through the code for IdentityUserLogin, I can see it has a property UserId which should be considered a primary key, right?

Anyway, to make sure its registered as a primary key, I added this code to ApplicationUser's OnModelCreating method: builder.Entity<ApplicationUser>().HasKey(u => u.Id);. I still get the same error! Not sure what I'm doing wrong here :(. Edit: Yes, I called the base class so that's not the problem.

Note: I know I can add a field to each user that carries a collection of todo item Ids instead of having a foreign key, but I'm not sure if that's the good way of doing this. Guidance on this issue appreciated.

解决方案

You haven't shared the code for this, but I'm guessing you have made an override of OnModelCreating in your db context, but have not called base.OnModelCreating(modelBuilder);.

Without the base call, your context isn't applying the Identity related schema.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Add Identity related model configuration
    base.OnModelCreating(modelBuilder);

    // Your fluent modeling here
}


Edit: Felt like giving this a whirl so I just performed the below tasks. The TLDR would be that it worked out for me. I believe the issue you are having has nothing to do with the key you are making and something unrelated is causing your failure, because the failure you are getting is on a completely different table than the one you are building schema for.

I created a new .net core web application using Identity. First thing I did was call update-database to build up the DB from the initial migration that the project came with. This worked.

Next I added a Todo class. No properties, just an Id and the User field. Didn't even mark the foreign key.

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

I added it to the ApplicationDbContext as a DbSet. Only alteration to the context was to add the ToDo DbSet

Then I called add-migration todo in the package manager console to build the todo migration. It generated as expected with the FK in place.

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");
    }
}

I then added some code to my About controller action to just stick a record into the table to make sure the FK was working. It was.

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

Screenshot of the record in the DB along with tables and keys:

Other than the obvious that you have more fields on your Todo class is there something drastically different that you've done differently that may lead us to the problem?

这篇关于如何在EF Core中向身份用户添加外键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆