簡體   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