😇

Exception: PostgrestException(message: there is no unique or exclusio

2024/02/13に公開

💡Tips

Supabaseにデータを追加しようとするとエラーが出た???
ポリシーの許可以外に、Columnに制約をつける必要があったみたいだ...
今回だと、user_nameというのに必要だった。

error log

ter: ----------------FIREBASE CRASHLYTICS---------------- flutter: Exception: PostgrestException(message: there is no unique or exclusion constraint matching the ON CONFLICT specification, code: 42P10, details: Bad Request, hint: null) flutter: #0 InputMyPage.build. (package:work_stream/supabase_pj/view/page/input_my_page.dart:218:23) flutter: -----------

AIに聞いてみた

エラーメッセージは、ON CONFLICT指定に一致する一意または排他制約がないことを示しています。これは、upsert操作で指定したonConflictパラメータが、データベースのテーブルに存在する一意性制約または排他制約と一致しないために発生します。

あなたのコードでは、onConflictパラメータに'user_name'が指定されています。これは、'user_name'カラムに一意性制約が存在することを前提としています。しかし、エラーメッセージから判断すると、そのような制約が存在しないようです。

この問題を解決するためには、以下の2つの方法が考えられます:

データベースのスキーマを変更して、'user_name'カラムに一意性制約を追加します。これにより、同じ'user_name'を持つ複数のレコードが存在しないことが保証されます。

コードを変更して、onConflictパラメータに一意性制約または排他制約が存在するカラム名を指定します。これは、'user_name'カラムに一意性制約を追加することが適切でない場合に適しています。

どちらの方法を選択するかは、あなたのアプリケーションの要件とデータベースの現在の状態によります。

SQLのクエリを直接実行して制約をつけるのが簡単だったので、これを実行した。

ALTER TABLE users
ADD CONSTRAINT unique_user_name UNIQUE (user_name);

今回使ったメソッドは、uuidと自動生成されるidの他に色々データを保存するメソッドですね。実験用に作ったのですけど、uuidがテーブルにないと、ログインしているユーザーを特定する情報がないので、追加しました💦

// ユーザーの新規登録
  Future<void> createUserOrUpdate(
      String userName,
      String dateText,
      String iconImagePath,
      String profile,
      String jobId,
      ) async {
    try {
      final session = SupabaseInstance().supabase.client.auth.currentSession;
      final user = session?.user;
      if (user?.id == null) {
        throw Exception('User ID is null');
      }
      final jaUtc = DateTime.now().toUtc().toIso8601String();
      await SupabaseInstance().supabase.client.from('users').upsert(
        {
          'uuid': user?.id,
          'user_name': userName,
          'birthday': dateText,
          'iconImagePath': iconImagePath,
          'job_id': jobId,
          'profile': profile,
          'created_at': jaUtc,
          'updated_at': jaUtc,
          'is_delete': false,
        },
        onConflict: 'user_name',
      );
    } on Exception catch (e) {
      logger.d('😇createUserOrUpdate error: $e');
      rethrow;
    }
  }

一応保存できた💦

まとめ

今回の記事は、Dartのロジックというより、Supabaseのエラーでハマったのでその解決方法を試してみた記事でした。気をつけることは、テーブル定義とColumnに名前が一致した引数をメソッドに書き忘れないようにすることです。

テーブル定義するとこんな感じですね。重要なのは、uuidが必要だってことと今回は、user_nameに制約をつけることでしたね。

Column Name Data Type Constraints
uuid UUID PRIMARY KEY
user_name VARCHAR(255) NOT NULL, UNIQUE
birthday DATE
iconImagePath TEXT
job_id INT
profile TEXT
created_at TIMESTAMP WITH TIME ZONE
updated_at TIMESTAMP WITH TIME ZONE
is_delete BOOLEAN DEFAULT FALSE

Discussion