web-dev-qa-db-ja.com

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

.NET CoreのIdentityパッケージを、IdentityUser<Guid>を拡張する複数のクラスで使用しますが、UserRoleクラスは1つだけです。

ユーザータイプごとにUserStore<T>を拡張する複数のクラスと、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>();

私のDbContextIdentityDbContextを拡張していません:

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.RoleManager1[Models.Entities.Users.UserRole] - and Instance 'Dal.IdentityStores.GenericUserRoleStore' for PluginType Microsoft.AspNetCore.Identity.IRoleStore1 [Models.Entities.Users.UserRole]-のインスタンス 'Dal.IdentityStores.GenericUserRoleStore' Microsoft.AspNetCore.Identity.IRoleStore1[Models.Entities.Users.UserRole] - and Instance 'Dal.IdentityStores.ContractorUserStore' for PluginType Microsoft.AspNetCore.Identity.IUserStore1 [Models.Entities.Contractors.Contractor]-およびPluginTypeのインスタンス「UserClaimsPrincipalFactory」Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1[Models.Entities.Contractors.Contractor] - and Instance 'UserClaimsPrincipalFactory<Contractor, UserRole>' for PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1 [Models.Entities.UserManagerとContractors.Contractors.Contractors.Contractors.Contractors.Contractors。 AspNetCore.Identity.UserManager1[Models.Entities.Homeowners.Homeowner] - and Instance 'UserClaimsPrincipalFactory<Homeowner>' for PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1 [Models.Entities.Homeowners.Homeowner]

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

8
Node.JS

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

複数のユーザーテーブルに対する主な理由は次の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");
    }

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

2
Vano Maisuradze

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

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

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

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

あなたは述べる:

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

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

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

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

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

0
Brian Ogden