web-dev-qa-db-ja.com

UserManagerを使用してIdentityUserにナビゲーションプロパティを読み込む方法

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; }
}
_
24
Mourndark

残念ながら、手動で行うか、独自の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);
22

簡単な答え:できません。ただし、オプションがあります。

  1. 後で関係を明示的にロードします。

    await context.Entry(user).Reference(x => x.Address).LoadAsync();
    

    もちろんこれには追加のクエリを発行する必要がありますが、UserManager経由でユーザーをプルし続けることができます。

  2. コンテキストを使用するだけです。 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は、実際に遅延読み込みをサポートします。)にもかかわらず、遅延読み込みはたいていの場合悪い考えです。そのため、関係を積極的にまたは明示的に読み込むことに固執する必要があります。

10
Chris Pratt

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());
}
0
Daniel Kahle