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; }
}
_
残念ながら、手動で行うか、独自の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);
簡単な答え:できません。ただし、オプションがあります。
後で関係を明示的にロードします。
await context.Entry(user).Reference(x => x.Address).LoadAsync();
もちろんこれには追加のクエリを発行する必要がありますが、UserManager
経由でユーザーをプルし続けることができます。
コンテキストを使用するだけです。 UserManager
を使用するのにhaveを使用しないでください。いくつかのことが少し簡単になります。コンテキストを介して直接クエリにいつでもフォールバックできます:
var user = context.Users.Include(x => x.Address).SingleOrDefaultAsync(x=> x.Id == User.Identity.GetUserId());
FWIW、ナビゲーションプロパティにvirtual
は必要ありません。これは、EF Coreが現在サポートしていない遅延読み込み用です。 (ただし、現在プレビュー中のEF Core 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());
}