我已经扩展IdentityUser
以包含用户地址的导航属性,但是当使用UserManager.FindByEmailAsync
获取用户时,不会填充导航属性。 ASP.NET Identity Core是否有某种方法来填充Entity Framework的Include()
等导航属性,或者我是否必须手动执行此操作?
我已经设置了这样的导航属性:
public class MyUser : IdentityUser
{
public int? AddressId { get; set; }
[ForeignKey(nameof(AddressId))]
public virtual Address Address { get; set; }
}
public class Address
{
[Key]
public int Id { get; set; }
public string Street { get; set; }
public string Town { get; set; }
public string Country { get; set; }
}
答案 0 :(得分:16)
不幸的是,您必须手动执行此操作,或者创建自己的IUserStore<IdentityUser>
,以FindByEmailAsync
方式加载相关数据:
public class MyStore : IUserStore<IdentityUser>, // the rest of the interfaces
{
// ... implement the dozens of methods
public async Task<IdentityUser> FindByEmailAsync(string normalizedEmail, CancellationToken token)
{
return await context.Users
.Include(x => x.Address)
.SingleAsync(x => x.Email == normalizedEmail);
}
}
当然,仅仅为此实施整个商店并不是最好的选择。
您也可以直接查询商店:
UserManager<IdentityUser> userManager; // DI injected
var user = await userManager.Users
.Include(x => x.Address)
.SingleAsync(x => x.NormalizedEmail == email);
答案 1 :(得分:10)
简短的回答:你做不到。但是,有选择:
稍后明确加载关系:
await context.Entry(user).Reference(x => x.Address).LoadAsync();
这当然需要发出额外的查询,但您可以继续通过UserManager
拉出用户。
只需使用上下文。您没有 使用UserManager
。它只是使一些事情变得更简单。您可以随时通过上下文直接回溯查询:
var user = context.Users.Include(x => x.Address).SingleOrDefaultAsync(x=> x.Id == User.Identity.GetUserId());
FWIW,您的导航属性不需要virtual
。这是懒惰加载,EF Core目前不支持。 (虽然,EF Core 2.1,目前正在预览中,实际上会支持延迟加载。)无论如何,延迟加载通常是一个坏主意,所以你仍然应该坚持或明确加载你的关系。
答案 2 :(得分:1)
我发现在UserManager类上编写扩展很有用。
public static async Task<MyUser> FindByUserAsync(
this UserManager<MyUser> input,
ClaimsPrincipal user )
{
return await input.Users
.Include(x => x.InverseNavigationTable)
.SingleOrDefaultAsync(x => x.NormalizedUserName == user.Identity.Name.ToUpper());
}