複数のユーザータイプのID-DbContextデザイン


8

.NET CoreのIdentityパッケージIdentityUser<Guid>を、単一のクラスで拡張された複数のクラスで使用しようとしていますUserRole

UserStore<T>ユーザータイプごとに拡張する複数のクラスと、拡張する1つのクラスがありますRoleStore<UserRole>

以下は私のstartup.csです:

services.AddIdentity<InternalUser, UserRole>(IdentityOptions)
    .AddDefaultTokenProviders()
    .AddUserStore<InternalUserStore>()
    .AddRoleStore<GenericUserRoleStore>();

services.AddIdentityCore<Contractor>(IdentityOptions)
    .AddRoles<UserRole>()
    .AddDefaultTokenProviders()
    .AddUserStore<ContractorUserStore>()
    .AddRoleStore<GenericUserRoleStore>();

services.AddIdentityCore<Homeowner>(IdentityOptions)
    .AddRoles<UserRole>()
    .AddDefaultTokenProviders()
    .AddUserStore<HomeownerUserStore>()
    .AddRoleStore<GenericUserRoleStore>();

DbContextは延長していませんIdentityDbContext

public sealed class EntityDbContext: DbContext { }

複数のエラーが発生したため、以下を追加しましたDbContextが、コメント化しました。

public DbSet<IdentityUserClaim<Guid>> UserClaims { get; set; }

public DbSet<IdentityUserRole<Guid>> UserRoles { get; set; }

さまざまなエラーが発生します。

PluginType IUserStoreのインスタンス 'Dal.IdentityStores.InternalUserStore'およびPluginTypeのインスタンス 'RoleManager'でビルドエラーが発生しましたMicrosoft.AspNetCore.Identity.RoleManager 1[Models.Entities.Users.UserRole] - and Instance 'Dal.IdentityStores.GenericUserRoleStore' for PluginType Microsoft.AspNetCore.Identity.IRoleStore1 [Models.Entities.Users.UserRole]-およびインスタンス 'Dal.IdentityStores.GenericUserRoleStore' PluginType Microsoft.AspNetCore.Identity.IRoleStore 1[Models.Entities.Users.UserRole] - and Instance 'Dal.IdentityStores.ContractorUserStore' for PluginType Microsoft.AspNetCore.Identity.IUserStore1 [Models.Entities.Contractors.Contractor] -及びPluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactoryのインスタンス'UserClaimsPrincipalFactory' 1[Models.Entities.Contractors.Contractor] - and Instance 'UserClaimsPrincipalFactory<Contractor, UserRole>' for PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1 [Models.Entities.Contractors.Contractor] -およびインスタンス'のUserManager'のPluginType Microsoft.AspNetCore.Identity.UserManager 1[Models.Entities.Homeowners.Homeowner] - and Instance 'UserClaimsPrincipalFactory<Homeowner>' for PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1 [Models.Entities.Homeowners.Homeowner]

これは私のリポジトリへリンクです


それで、あなたの質問は何ですか?
Vano Maisuradze

コードが機能しません。上記のエラーが発生します。複数のタイプを「ユーザー」として使用するように修正するにはどうすればよいですか。
Node.JS

私はあなたのリポジトリをクローンしました、そしてそれは私のために働いたので、おそらくそれはあなたの環境問題です。
Vano Maisuradze

1
@VanoMaisuradzeユーザーを作成してサインインしてください。問題が表示されます。登録/ログイン用のコントローラーがあります
Node.JS

1
はい、そうしました。ありがとう
Node.JS

回答:


2

私はあなたの問題を再現しましたが、以下はその解決策ですが、ユーザーの役割ごとに複数のテーブルを作成することをもう一度考えます。

複数のユーザーテーブルに対する主な理由は次の2つです。

  1. IDでユーザーを検索する場合(役割がわからない場合)、さまざまなテーブルに対して複数のクエリを実行する必要があるため、パフォーマンスが低下し、コードが複雑になります。
  2. また、他のテーブルに複数の外部キーを設定する必要があるため、データベースが複雑になる可能性もあります。

それでも、異なるユーザーロール用に複数のテーブルが必要な場合は、ここに小さな「ハック」があります。OnModelCreatingメソッドをオーバーライドしてエンティティを構成するだけです。

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Contractor>(b =>
        {
            b.HasMany<IdentityUserRole<Guid>>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
        });

        builder.Entity<UserRole>(b =>
        {
            b.HasKey(r => r.Id);
            b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique();
            b.ToTable("AspNetRoles");
            b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();

            b.Property(u => u.Name).HasMaxLength(256);
            b.Property(u => u.NormalizedName).HasMaxLength(256);

            b.HasMany<IdentityUserRole<Guid>>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
            b.HasMany<IdentityRoleClaim<Guid>>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
        });

        builder.Entity<IdentityRoleClaim<Guid>>(b =>
        {
            b.HasKey(rc => rc.Id);
            b.ToTable("AspNetRoleClaims");
        });

        builder.Entity<IdentityUserRole<Guid>>(b =>
        {
            b.HasKey(r => new { r.UserId, r.RoleId });
            b.ToTable("AspNetUserRoles");
        });

        builder.Entity<UserRole>().ToTable("Roles");
        builder.Entity<IdentityUserRole<Guid>>().ToTable("UserRoles");
        builder.Entity<IdentityRoleClaim<Guid>>().ToTable("RoleClaims");
        builder.Entity<IdentityUserClaim<Guid>>().ToTable("UserClaims");
    }

その後、ログインできるはずです。


0

OPがコメントで説明した要件と、OPはデータベース設計の経験がないと述べた要件に基づいて、OPのプロジェクトとソフトウェア開発のキャリアをより快適にするのに役立つ可能性がある回答を提供しようとします。

まず、単一の「ユーザー」テーブルが必要です。

|---------------------|------------------|------------------|
|      FirstName      |     LastName     |       Role       |
|---------------------|------------------|------------------|
|          Joe        |       Black      |     Contractor   |
|---------------------|------------------|------------------|

プロジェクトに複数のユーザーテーブルを用意する必要はありません。また、プロジェクトやソフトウェア製品では、一般的に言えば、そのようなことは必要ありません。ユーザーテーブルが数十億のレコードにスケーリングされる場合、パフォーマンスのためにパーティション間でシャーディングされたり、読み取りと書き込みで非正規化されたりする場合でも、スケーリングされた多くの複雑なソフトウェアシステム設計では論理的に1つのテーブルになります。

あなたは述べる:

ユーザーの種類ごとに異なるユーザーメタデータを設定するにはどうすればよいですか?請負業者には独自のプロパティがあり、住宅所有者には独自のプロパティセットがあります。可能なすべてのプロパティを備えた巨大なテーブルを作成したくない

あなたの懸念は、あなたが巨大なテーブルに終わらないことです。要するに、これはあなたにとって問題ではありません。巨大なテーブルはまだありません。30列(「プロパティ」と言ったとおり)を追加した場合、巨大なテーブルにはなりません。

単一のユーザーテーブルを作成します。特定の請負業者のプロパティにnull許容列を追加し、特定の住宅所有者のプロパティにnull許容列を追加します。プロパティがすべてのユーザーに適用される場合は、列をNull以外にします。

すべてのユーザーに適用される列はユーザ​​ーのロール列であるため、「ロール」と呼ばれるNull不可の列があります。

リレーショナルデータベースを使用している場合、ロール行レコードを含むロールテーブルを作成する必要はありません。あなたはこれを行うことができ、コースの講師はそれを期待するかもしれませんが、可能なロールを表すconst文字列クラスまたは列挙を作成することもできます。これは、これらのロールに整合性を提供する永続化の形式です。これは、開発者がリレーショナルデータベースの設計で参照整合性の過剰にすぐに踏み込む領域だからです。


1
申し訳ありませんが、あなたの答えはすでに提案した提案です。これは、OPの質問に直接回答するものではありません。また、null許容列を作成することは良い解決策ではないかもしれません。たとえば、Jsonを使用すると、よりクリーンになる可能性があります。
Vano Maisuradze

いいえ、それはほんの提案にすぎません。ソリューションにアプローチして実装するための丁寧に表現された正しい方法です。
ブライアンオグデン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.