UserManager未正确更新自定义标识用户

时间:2016-11-26 17:30:20

标签: c# asp.net-identity .net-core

我使用aspnet Identity + 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,则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); 
    }

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

2 个答案:

答案 0 :(得分:0)

您的媒体资源应标记为虚拟。如果记录存在于您的数据库中,但是当您运行GET方法并为用户获取数据时,这些记录还没有被提取,那么它是由于延迟加载而导致的。当您访问用户对象时,virtual关键字将允许填充它们。

这就是你想要的:

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

答案 1 :(得分:0)

_userManager.GetUserAsync方法中,您必须编写代码以急切加载StudyTags,如下所示:

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

如果您的属性是虚拟的,那么只有在您访问该属性时才会加载它(延迟加载)。如果您的属性不是虚拟的,则应在加载保存属性的对象时加载它。

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

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

上面的开关具有全局效果,所以如果不小心它会导致性能问题,因为每次都会加载整个对象图,即使你可能不需要它。

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