lycheejam's tech log

チラ裏のメモ帳 | プログラミングは苦手、インフラが得意なつもり。

EF CoreとMySQLでDuplicate entry '0' for key 'PRIMARY'エラーが発生

概要

.NET CoreでDocker上で稼働しているMySQLをいろいろこねくり回してるんですが
タイトルのエラーが出て辛かったので対応手順のメモです。

  • 関連ツイート

目次

環境

  • MacOS Mojave Version 10.14.3
  • .Net Core SDK Version 2.2.104
  • Docker Version 18.09.2
    • Docker image : MySQL 5.7(公式)

参考サイト様

事象

Login画面に遷移し外部認証(Twitter)を実施。
その後、メールアドレスを登録するが登録した際に以下のエラーが発生する。

An unhandled exception occurred while processing the request.
MySqlException: Duplicate entry '0' for key 'PRIMARY'
MySqlConnector.Core.ServerSession.TryAsyncContinuation(Task<ArraySegment<byte>> task) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs, line 1252

MySqlException: Duplicate entry '0' for key 'PRIMARY'
MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet(ResultSet resultSet) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs, line 81

DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)

f:id:HM_Atlas:20190303014324p:plain

原因

外部認証(Twitter)を実行した際に独自のClaimをDBに登録している。
DBにデータを登録する際の動作としてAspNetUserClaimsテーブルにデータを登録する。
該当テーブルはプライマリーキーにIdカラムが存在するのだが該当のカラムはEntityFrameworkのコード上、自動採番のカラムとなっている。
しかし、DBテーブルの実態としてはauto_increment属性が付与されておらず自動採番がされなかったため主キーが抜け落ちてる状態となり上記のエラーが発生した。

※該当カラムが自動採番で有ることは確認済み。

また、本事象が発生した原因はWindows端末のVisualStudio 2017にてプロジェクトを作成した後
GitHub経由でMac環境へ共有し開発用DBとしてDocker上で稼働するMySQLを使用したが
Oracle公式の接続プロバイダからOSSの接続プロバイダであるPomeloへの切り替えなど多数の変更があったためMigrationの記録がうまくDBに反映されなかったためと推察される。

  • 該当のテーブル
mysql> DESC TODOAPP.AspNetUserClaims;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| Id         | int(11)      | NO   | PRI | NULL    |       |←auto_incrementが付与されていない
| UserId     | varchar(767) | NO   | MUL | NULL    |       |
| ClaimType  | text         | YES  |     | NULL    |       |
| ClaimValue | text         | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+

対策

結論としてはDBテーブルを作成し直す。
(今回は開発用DBであるため碌なデータがないのでデータバックアップ等には触れない。)
下記手順をプロジェクトディレクトリにて実行する。

DBの削除

$ dotnet ef -v database drop

Migration(履歴)の削除

migrationの一覧を確認する。

$ dotnet ef migrations list

migration(履歴)を削除する。
※Migrationの件数分、繰り返す

一括削除の方法はわからなかったので誰か教えてください。
(ファイルを手動で削除して__MigrationHistoryのデータも手動削除してやればよかったのかな?)

$ dotnet ef migrations remove -v -f

Database Update

DatabaseUpdateをかけてテーブルの再作成を実行。

$ dotnet ef migratoions add init
$ dotnet ef database update

結果確認

DBにてテーブルを確認すると属性が付与されていることが確認できます。
また、画面でもエラー無く操作できることが確認できます。

mysql> select * from TODOAPP.AspNetUserClaims;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| Id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| UserId     | varchar(255) | NO   | MUL | NULL    |                |
| ClaimType  | longtext     | YES  |     | NULL    |                |
| ClaimValue | longtext     | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

雑感

多分、Oracle公式の接続プロバイダ使ってるときにMigration一回したんだけど
それでうまく属性が反映されてなかったっぽい。