web-dev-qa-db-ja.com

EF-CoreでID /プライマリキーに文字列ではなくGUIDを使用する方法

ASP.NET 3 IDを見ると、一意の主キーにstringではなくGuidを使用しています。

Entity Frameworkcode firstユーザーのApplicationUserクラスでは、Identityクラスを継承します

public class ApplicationUser : IdentityUser
{
}

entity Frameworkの移行を作成すると、aspnetusersの代わりにnvarchar(450)のキータイプでテーブルuniqueidentifierが作成されます。

これをASP.NET Identity 2ENtity Frameworkプロジェクトと比較すると、nvarchar(450)ではなくuniqueidentifierのIDフィールドが作成されました

データベースのパフォーマンスのために、uniqueidentifierの主キーと外部キーはnvarchar(450)よりも優れていると思います

ASP.NET Identity 3nvarchar(450)の代わりにGuidおよびstringの代わりにuniqueidentifierの一意のキーに使用する方法はありますか?

前の質問 StringをGUIDに変換する方法がありますが、データベーステーブルIDをGUIDにしたいです。

長さがnvarchar(128)であった場合、以前のベータ版でも別の question が見つかりました。指定された理由は、すべてのデータベースがGUIDをサポートしているわけではなく、柔軟性のために変更されたためです。

identity 3全体を書き換えずに文字列からGuidに変更する簡単な方法が必要ですか?

nvarchar(450)は本当に過剰であり、SQL Serverデータベースの制約を作成するときにあらゆる種類の警告を出します。データベース管理者は間違いなくこれらの警告を好まないでしょう。

19
devfric

カスタムApplicationUserIdentityUser<TKey>から継承し、カスタムロールはIdentityRole<TKey>から継承する必要があります

public class ApplicationUser : IdentityUser<Guid> { }    
public class Role : IdentityRole<Guid> { }

カスタムコンテキストクラスはIdentityDbContext<ApplicationUser, Role, TKey>を継承し、流uidなapiを使用してGUIDキーを自動生成します。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Role, Guid>
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<ApplicationUser>(b =>
        {
            b.Property(u => u.Id).HasDefaultValueSql("newsequentialid()");
        });

        builder.Entity<Role>(b =>
        {
            b.Property(u => u.Id).HasDefaultValueSql("newsequentialid()");
        });
    }
}

次に、スタートアップでこのようなコンテナにIdentityサービスを追加します

services.AddIdentity<ApplicationUser, Role>()
        .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
        .AddDefaultTokenProviders()
        .AddUserStore<UserStore<ApplicationUser, Role, ApplicationDbContext, Guid>> ()
        .AddRoleStore<RoleStore<Role, ApplicationDbContext, Guid>>();

データベースを作成していない場合は、移行フォルダーをクリアしてefコマンドを実行します

41
tmg

私はまだこの例の移行をいじっていません(いくつかの調整が必要な場合があります)が、ASP.NET Identity v3は、この点でv2よりもはるかに拡張可能です。

以下は、ユーザーとロールの両方のGUID主キーに基づくIDストアを提供するはずです。

public class ApplicationUser : IdentityUser<Guid>
{
}

public class GuidDataContext :
    IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
}

そしてあなたのスタートアップクラスで:

services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
            identity =>
            {
                // whatever identity options you want
                identity.User.RequireUniqueEmail = true;
                identity.Password.RequiredLength = 8;
            }).
            AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders();

同様に、カスタムユーザーにカスタムフィールドを追加したり、オプションをカスタマイズしたりする必要がない場合は、次の操作を実行できます。

public class GuidDataContext :
    IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid>
{ 
}

そしてあなたのスタートアップで:

services
    .AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>()
    .AddEntityFrameworkStores<GuidDataContext, Guid>()
    .AddDefaultTokenProviders();
9
Ron DeFreitas

ApplicationUserは、 IdentityUser をidとして文字列を持つものとして定義されている基本クラスから継承します。そのため、実際にguid/uniqueidentifierを使用するには、その基本クラスから継承しないようにする必要があります。

内部的にはidにguid文字列を使用していることに注意してください。少なくとも、次のようにキーのフィールドサイズを制限できる必要があります。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<ApplicationUser>(b =>
        {
            // you could limit the field size to just long enough for a guid id as string
            b.Property(p => p.Id)
                .HasMaxLength(36);

            // instead, you could define the id as Guid but more work required
            //b.Property(p => p.Id)
            //   .ForSqlServerHasColumnType("uniqueidentifier")
            //   .ForSqlServerHasDefaultValueSql("newid()")
            //   .IsRequired();

        });

    }
}

キーにGuids/uniqueidentifierを使用できますが、独自の基本クラスを使用する(または基本クラスをまったく使用しない)だけでなく、より多くの作業が必要になり、カスタムDbContextを使用してモデルをマップします。 ここからのEFコード を借りて変更すると、うまくいきます。 serStore から継承し、IDでユーザーを検索するための仮想メソッドをオーバーライドする必要があります。 IUserStore は、FindByIdメソッドシグネチャを文字列で定義します。したがって、オーバーライドするには、IDで取得または検索する必要があるメソッド内で文字列をGUIDに変換する必要があります。

私は cloudscribeプロジェクト でそれを正確に行っています。これはIdentityのカスタムマルチテナント実装を持っています

編集:実際にコードを詳しく見ると、IdentityUserにはキーのタイプを定義できる汎用バージョンがあります

public class IdentityUser<TKey> where TKey : IEquatable<TKey>

したがって、次のように独自の基本クラスを定義することができるかもしれません

IdentityUser<Guid>

ただし、ID文字列を取得して文字列をGUIDに変換するUserStoreメソッドをオーバーライドする必要があると思います。

2
Joe Audette