繁体   English   中英

UserManager无法正确更新自定义身份用户

[英]UserManager not updating custom Identity User properly

我正在使用ASP.NET身份+ OpenIddict在EF Core上进行身份验证。

我扩展了IdentityUser类,使其包括两个列表。 StudyTagsExpertTags以及其他一些属性:

public class ApplicationUser : IdentityUser
{
    public ApplicationUser()
    {
        StudyTags = new List<Tag>();
        ExpertTags = new List<Tag>();
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Location { get; set; }
    public List<Tag> StudyTags { get; set; }
    public List<Tag> ExpertTags { get; set; }
}

这一切都很好,但是,当我想更新这些列表并保存它们时,更新似乎只在一定范围内持续存在。 例如,如果我两次调用下面的API调用,则第一次将标记添加到正确的列表中,而第二次记录一条消息,表明它已被添加。 我可以检查用户并验证标签是否如预期的那样在列表中。

    [Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
    [HttpPost("add/tag/{tagType}/{tagName}")]
    public async Task<IActionResult> AddTagToUser(int tagType, string tagName) 
    {
        var user = await _userManager.GetUserAsync(User) as ApplicationUser;
        if(user == null) 
        {
            _logger.LogError("User not found");
            return BadRequest();
        }

        TagType type = (TagType)tagType;

        var tag = _tagService.GetTagByName(tagName);
        if(tag == null)
        {
            _logger.LogError("No tag corresponding to tagName '{0}'", tagName);
            return BadRequest();
        }

        if(type == TagType.Study)
        {
            if(user.StudyTags.Contains(tag))
            {
                _logger.LogInformation("{0} already assigned to {1}", tag.ToString(), user.ToString());
            }
            else
            {
                _logger.LogInformation("{0} added to {1}", tag.ToString(), user.ToString());
                user.StudyTags.Add(tag);
            }
        }
        else if(type == TagType.Expert)
        {
            if(user.ExpertTags.Contains(tag))
            {
                _logger.LogInformation("{0} already assigned to {1}", tag.ToString(), user.ToString());
            }
            else 
            {
                _logger.LogInformation("{0} added to {1}", tag.ToString(), user.ToString());
                user.ExpertTags.Add(tag);
            }
        }
        else
        {
            _logger.LogError("No tagType corresponding to {0}", tagType);
            return BadRequest();
        }


        var result = await _userManager.UpdateAsync(user);

        if(result.Succeeded)
        {
            return Ok(result);
        }
        else
        {
            _logger.LogError("Updating Tag failed");
            return BadRequest();
        } 
    }

但是,如果我只是尝试Get同一用户的Get ,则StudyTags和ExpertTags列表为空。

    [Authorize(ActiveAuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var user = await _userManager.GetUserAsync(User);
        if(user == null)
        {
            _logger.LogError("User not found");
            return BadRequest();
        }

        return Ok(user); 
    }

我做错了什么吗? 任何帮助,将不胜感激!

您的属性应标记为虚拟。 如果记录存在于数据库中,但是在运行GET方法并为用户获取数据时未获取记录,则是由于延迟加载。 当您访问用户对象时,虚拟关键字将允许它们被填充。

这就是你想要的:

public virtual List<Tag> StudyTags { get; set; }
public virtual List<Tag> ExpertTags { get; set; }

更新:

因此,看起来需要一个M:M关系。 由于EF Core不支持联结类的自动创建,因此必须显式进行。 因此,最后,您的模型必须如下所示:

public class ApplicationUser : IdentityUser 
{
    //Other Properties
    public ICollection<Tag> StudyTags { get; set; }
    public ICollection<Tag> ExpertTags { get; set; }
}

public class Tag
{
    //Other Properties
    public ICollection<ApplicationUser> Users { get; set; }
}

public class UserTags 
{
    public int UserId { get; set; }
    public ApplicationUser User { get; set; }

    public int TagId { get; set; }
    public Tag Tag { get; set; }
}

并且您的上下文需要更新为包括:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<UserTag>()
        .HasKey(x => new { x.User, x.TagId });

    modelBuilder.Entity<UserTag>()
        .HasOne(x => x.User)
        .WithMany(y => y.UserTags)
        .HasForeignKey(x => x.UserId);

    modelBuilder.Entity<UserTag>()
        .HasOne(x => x.Tag)
        .WithMany(y => y.UserTags)
        .HasForeignKey(x => x.TagId);
}

_userManager.GetUserAsync方法中,您必须编写代码以像下面这样急切地加载StudyTag:

context.User.Include(x => x.StudyTags).Include(x => x.ExpertTags);

如果您的属性是虚拟的,则仅在您访问该属性时才将其加载(延迟加载)。 如果您的属性不是虚拟的,则应在加载包含该属性的对象时加载它。

如果要全局关闭延迟加载,可以将其包含在上下文构造函数中:

this.Configuration.LazyLoadingEnabled = false; // careful though keep reading

上面的开关具有全局作用,因此,如果不小心,可能会导致性能问题,因为即使您可能不需要,整个对象图也会每次加载。

要关闭单个属性的延迟加载,请将其设置为NON虚拟。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM