質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

ASP.NET MVC Framework

ASP.NET MVC Frameworkは、MVCパターンをベースとした、マイクロソフトのウェブアプリケーション開発用のフレームワークです。

Q&A

解決済

1回答

2756閲覧

ASP.NETの認証機能のAspNetUsersテーブルに自動採番(identity)のカラムを追加すると更新時にエラーになる

woodcube

総合スコア32

.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

ASP.NET MVC Framework

ASP.NET MVC Frameworkは、MVCパターンをベースとした、マイクロソフトのウェブアプリケーション開発用のフレームワークです。

0グッド

0クリップ

投稿2021/02/23 05:51

編集2021/02/24 05:47

前提・実現したいこと

ASP.NET Coreでユーザが複数の店舗情報を持つDBの作成をしています。
店舗テーブルに、ユーザのIDを持たせ、所有者がわかるようにします。

店舗テーブルに、認証機能のユーザID(AspNetUsers.Id)を持たせようとしましたが、
IdはGUIDで長く読みにくい為、int型に変更して自動採番をさせようとしました。
ただ、AspNetUsers.Idをint型などにすると、Roleなど他のテーブルへの影響があり、
nvarchar型のままでユニークで短い文字列を生成するよりは、クラスを継承して
int UserId(auto increment)を追加する事にしました。
※認証系は既存のAspNetUsers.Id(GUID)で扱い、
ビジネスロジック系はAspNetUsers.UserId(int)で識別するという事です。

認証機能の登録の過程の「Click here to confirm your account」をクリックするとエラーになってしまいます。

対処・対応の方法として、次の4パターンを考えました。
1.店舗レコードへ書くUser識別を諦めてGUIDにしておく(できれば避けたい)
2.ユーザIDをGUIDなくロジックで生成する(重複なく生成する必要がある)
3._userManager.ConfirmEmailAsyncでUserIdの項目が更新対象になっている(からエラーになると思われる)ので、ここを見直す(方法が分からない)
4.更新対象のレコード・カラムをピンポイント(SQL文を発行)で更新する(ここだけSQL?)

「2.」の方法で確実にIdを生成する方法が思いつきません
→Count+1とか、ランダム生成して重複してないかチェックするのは賢いとは思えない
「3.」のケースで特定の項目だけ更新の対象外にする方法とかがあるのでしょうか?

※個人的には「2.」でうまく生成できる方法が後々にも楽なのかと思っています。

やった事

・ASP.MET COREでWEBアプリケーションを作成(認証は無しで作成)。
・新規スキャフォールディングでIDを指定し認証を有効にする(すべてのファイルをオーバーライド)。
・認証のユーザクラスIdentityUserに対して継承を行い、App01FindUserを作成しUserIdを追加。この項目をDatabaseGeneratedOption.Identityでauto incrementに指定↓

C#

1public class App01FindUser : IdentityUser 2{ 3 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  4 public int UserId { get; set; } 5}

・マイグレーションとアップデートを行い、テーブルを作成。
イメージ説明

・ユーザを登録し、「Click here to confirm your account」をクリックするとエラーになります。
Email Confirmは、下記の「エラーが発生する該当のソースコード」に載せてあります。
新規スキャフォールディングでオーバーライドしてから何も変更していません。
(userIdという変数がありますが、元々あり今回のUserIdとは正しく区別されてるようです)
※データは実際に登録されています。
※UserIdはauto increment指定なので、設定不要という認識で一切値を設定していません。

発生している問題・エラーメッセージ

イメージ説明

エラーが発生する該当のソースコード

ConfirmEmail.cshtml.cs

C#

1namespace App01Find.Areas.Identity.Pages.Account 2{ 3 [AllowAnonymous] 4 public class ConfirmEmailModel : PageModel 5 { 6 private readonly UserManager<App01FindUser> _userManager; 7 8 public ConfirmEmailModel(UserManager<App01FindUser> userManager) 9 { 10 _userManager = userManager; 11 } 12 13 [TempData] 14 public string StatusMessage { get; set; } 15 16 public async Task<IActionResult> OnGetAsync(string userId, string code) 17 { 18 if (userId == null || code == null) 19 { 20 return RedirectToPage("/Index"); 21 } 22 23 var user = await _userManager.FindByIdAsync(userId); 24 if (user == null) 25 { 26 return NotFound($"Unable to load user with ID '{userId}'."); 27 } 28 29 code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); 30 var result = await _userManager.ConfirmEmailAsync(user, code); //←ここでエラー 31 StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; 32 return Page(); 33 } 34 } 35}

補足情報(FW/ツールのバージョンなど)

Visual Studio 2019
ASP.NET CORE 5

うまくいかなかった原因

回答者の協力により、下記の事が分りました。

AspNetUsersの更新は、変更箇所以外のカラムもすべて更新対象としており、auto incrementのカラムはエラーになる事がわかりました。
コーディングの量に対して効果が低いので、auto incrementのカラムは諦めました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/02/23 07:23

情報不足です。ASP.NET Core Identity 関係の実装はどうしたのか、プロファイル情報 (UserId) の追加はどのように行ったのか、DB にはどのように反映されているのか、ユーザー登録の際 UserId はどのように登録してるのか、Email Confirmation 関係の実装はどのようにしているのか、エラーメッセージを見ると SQL Server で言う Identity 列を更新しようとして(そんなことはできない)エラーになっているようだがどうしてそんなことをしているのか等々詳しく書いてください。
退会済みユーザー

退会済みユーザー

2021/02/23 07:26

質問の「対処・対応の方法としては」にいろいろ書いてありますが、結局何がしたいのでしょう?
woodcube

2021/02/23 07:52 編集

結局は、「AspNetUsers.Idへの値をGUIDでなく重複していない連番を振っていきたい」です。 AspNetUsers.Idへ、好きな文字を書く方法は実現できているのですが、 「重複をせずに連番を振る」方法として「テーブルにロックをかけて存在する最大値を調べて+1した値」が最適(確実に重複しておらず、複雑でないロジック)な方法なのでしょうか? その場合、ロックの方法というのと、AspNetUsers.Idが簡易な数字にした場合の問題点(ロジック的には問題なくてもセキュリティやシステムの運用上は?)が気になります。 (質問の修正依頼は今から見直しします)
退会済みユーザー

退会済みユーザー

2021/02/23 08:45

「Email Confirmation 関係の実装はどのようにしているのか」に返答してください。
退会済みユーザー

退会済みユーザー

2021/02/23 11:04

今は使ってないようですが、今後使うのか使わないのかどうするのですか?
woodcube

2021/02/23 11:51

店舗テーブルにユーザ情報((AspNetUsers)を特定するID(またはUserId)を入れるのは決定です。 AspNetUsers.IdにGUIDでなく(nvarchar型のままで)自動採番の数字が入れられるのならば、AspNetUsers.Idを採用し、UserIdは不要になり使いません。 teratailの使い方の話になってくるのですが、 今の段階では、この質問は保留にしておいて、別途AspNetUsers.Idへの採番方法の質問を行い、その質問に対して解決した時点で、こちらの質問をクローズなどの扱いをとるのが良いのでしょうか?
退会済みユーザー

退会済みユーザー

2021/02/23 12:11

話は通じてますでしょうか?  「Email Confirmation 関係の実装はどのようにしているのか」について、今は使ってないようですが、今後使うのか使わないのかどうするのですか?・・・をお聞きしてます。
woodcube

2021/02/23 12:42

ごめんなさい、勘違いしてました。 今はデフォルトのままですが、最終的にはきちんと実装する予定です。 今はローカルでメールが送れないとかで動作確認出来ないのでいじってないですが、そのうちazureに搭載してemail confirmationは必須にするつもりでいます。 お手数おかけします
退会済みユーザー

退会済みユーザー

2021/02/23 13:22

そうですか、使わないのであればデフォルトで options.SignIn.RequireConfirmedAccount が true に設定されているのを false にすれば対症療法的には・・・とか思っていたのですが。明日また考えてみます。
guest

回答1

0

ベストアンサー

まずエラーになる原因ですが、質問者さんが質問に書いた、

3._userManager.ConfirmEmailAsyncでUserIdの項目が更新対象になっている(からエラーになると思われる)ので、ここを見直す(方法が分からない)

というのはその通りのようで、ConfirmEmailAsync メソッドで Identity の UserId フィールドも更新しようとするからのようです。

以下の画像は EF Core のログを Visual Studio の「出力」ウィンドウに表示できるようにし、ユーザー登録後に RegisterConfirmation ページのリンク "Click here to confirm your account" をクリックして ConfirmEmail ページを呼び出し、_userManager.ConfirmEmailAsync(user, code) を実行したときのものです。

イメージ説明

AspNetUsers テーブルの EmailConfirmed フィールドのみ false ⇒ ture に更新すれば良いところ、他のフィールドにも更新前と同じ値が渡されて UPDATE されています。

上の画像の例では、プロファイル情報に HandleName を追加しています。それにも値が渡され UPDATE されています。上の例は、質問者さんのケースと違って Identity 列ではなく、ただの NVARCHAR(128) なので問題なく UPDATE できています。

「ここを見直す」には ConfirmEmailAsync メソッドの実装を書き直す他ありませんが、それは現実的ではなさそうです。無理にやったとしても、直すのはそこだけでなく、Account/Manage/Index 他のページでユーザー情報の更新を行うときに使う _userManager.UpdateAsync(user) なども直さないと同じ問題が出ます。

イメージ説明

というわけで現実的なのは、追加プロファイル情報 UserId を Identity にするのをやめて普通に int 型にしておき、

2.ユーザIDをGUIDなくロジックで生成する(重複なく生成する必要がある)

という選択肢になるかと思います。(他の選択肢 1 と 4 はやる気はないと理解)

「2.」の方法で確実にIdを生成する方法が思いつきません
→Count+1とか、ランダム生成して重複してないかチェックするのは賢いとは思えない

「賢いとは思えない」とのことですが、Identity にできない以上は Register.cshtml.cs の実装の中で何とか重複してない Id を取得して設定する他なさそうです。

そこがどうしても気に入らなければ、選択肢 1 に戻るか、Id に代えて UserName を使うか(UserName は一意になるようになっています)、Id に int 型 Identity を使うよう ASP.NET Core Identity を独自実装する(以下の記事参照)ということになると思います。

ASP.NET Core Identity 独自実装(その1)
http://surferonwww.info/BlogEngine/post/2020/09/04/custom-storage-providers-for-aspnet-core-identity.aspx

上の独自実装案が、質問者さんが質問のコメントに書いた、

結局は、「AspNetUsers.Idへの値をGUIDでなく重複していない連番を振っていきたい」です。

に近いものだと思います。だた、これに Role の実装と、さらには Email Confirmation の実装まで追加しないと望む形にはならないと思いますので、そこまで時間と労力をかけてやる価値があるかは疑問ですが。

投稿2021/02/24 02:55

編集2021/02/24 03:27
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

woodcube

2021/02/24 05:35

詳しく調べていただきありがとうございます。 やはり、更新の必要が無い項目まで更新しようとしていた訳ですね。 深い所までのステップ実行ができてなかったのですが、EF Coreのログを取れば良いというのが勉強になりました。 UserIdは中止して、IdにGUIDでなく自動採番していく方法にします。 (重複しないIDの生成は、職業プログラマだった昔に、空き番が見つけられずInsertがどんどん遅くなるシステムを見た事があるので敬遠してました。そもそも桁数が少なすぎる仕様なのが問題でしたが゙・・・) UserNameは途中変更を認める予定ですので、これをキーにするのは止めておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問