将现有数据库条目/对象链接到数据库中另一个对象的属性?

时间:2016-11-07 20:21:52

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

我正在尝试在ApplicationUser上更新名为Municipality的属性。问题是,Municipality属性是一个已经存在于市政当局数据库表中的相关对象,所以我需要创建一个链接,而不仅仅是设置市政财产(在数据库中创建一个重复的市政当局)

我听说暴露外键可能是正确的方向(即明确地向ApplicationUser类添加一个MunicipalityId属性),如下所示:

public class ApplicationUser : IdentityUser
{
    ...

    public int? MunicipalityId { get; set; }

    [ForeignKey(nameof(MunicipalityId))]
    public Municipality Municipality { get; set; }
}

...但是当使用以下代码设置MunicipalityId时,user.Municipality仍然为null

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> SelectRegion(SelectRegionViewModel selectRegionViewModel, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        var user = await _userManager.GetUserAsync(HttpContext.User);

        if (user == null)
        {
            ...
        }
        else
        {
            user.MunicipalityId = selectRegionViewModel.SelectedMunicipality;

            using (var context = new ApplicationDbContext(
                _serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
            {
                context.Entry(user).State = EntityState.Modified;
                context.SaveChanges();
            }

            await _userManager.UpdateAsync(user);
        }

        return RedirectToAction(nameof(HomeController.Index), "Home");
    }

如果我设置了外键,是否需要执行一些额外的步骤?查看dbo.AspNetUsers数据库表中的条目,看起来用户的Municipality已经设置正确,因为MunicipalityId已设置,但user.Municipality在上面的代码中始终为null(即使应用程序启动时也是如此) ApplicationUser具有有效的MunicipalityId)

1 个答案:

答案 0 :(得分:0)

似乎我在正确的轨道上暴露了外键,只需要在ApplicationUser类上找到一种干净的方式来自定加载自定义属性Municipality。我这样做是通过创建一个自定义的UserStore类,其中包括Municipality:

public class ApplicationUserStore : UserStore<ApplicationUser>
{
    public ApplicationUserStore(ApplicationDbContext context)
        :base(context)
    {
    }

    public override Task<ApplicationUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
    {
        return Users
            .Include(u => u.Municipality)
            .Include(u => u.Roles)
            .Include(u => u.Claims)
            .Include(u => u.Logins)
            .FirstOrDefaultAsync(u => u.Id == userId);
    }
}

然后让框架通过在Startup ConfigureServices方法的这一部分中添加.AddUserStore来使用这个类:

    public void ConfigureServices(IServiceCollection services)
    {
        ...

        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
            options.Password.RequireDigit = true;
            options.Password.RequireLowercase = false;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
            options.Password.RequiredLength = 6;
        })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders()
            .AddUserStore<ApplicationUserStore>();

这实现了UserManager将返回填充了Municipality的用户,无需创建ApplicationDbContext并通过userManager查询我的查询

var user = await _userManager.GetUserAsync(HttpContext.User);