我使用aspnet Identity + OpenIddict在EF Core上进行身份验证。
我扩展了IdentityUser
类以包含两个列表; StudyTags
和ExpertTags
以及其他一些属性:
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);
}
我做错了什么吗?任何帮助将不胜感激!
答案 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。