web-dev-qa-db-ja.com

Laravelリレーションシップがまだアタッチされていない場合はアタッチされます

リレーションシップがまだアタッチされていない場合、すばやくアタッチする方法はありますか?このコードを使用してモデルの関係を更新しています。

        if (!empty($request->get('roles')) && is_array($request->get('roles'))) {
            $message->Roles()->attach($request->get('roles'));
        }
        if (!empty($request->get('users')) && is_array($request->get('users'))) {
            $message->Users()->attach($request->get('users'));
        }

しかし、私はこのエラーを受け取っています。

SQLSTATE [23000]:整合性制約違反:1062キー 'PRIMARY'のエントリ '1-41'が重複しています(SQL:insert into message_usermessage_iduser_id)値(1、41)、(1、42)、(1、43)、(1、44)、(1、45)、(1、46)、(1、47)、(1、48 )、(1、49)、(1、50))

まだ接続されていないユーザーの配列チェックの非常に長いリストを調べて、それらを接続することは避けたいです。これが唯一の方法かどうかも教えてください。

私は何かを考えています。

$message->Users()->attachIfNotAttached($request->get('users'));
10
user5500750

このような何かがうまくいくかもしれません:

すでに添付されているIDを取得します。

$attachedIds = $message->Users()->whereIn('id', $request->get('users'))->pluck('id');

添付されたIDをリクエスト配列から削除します。

$newIds = array_diff($request->get('users'), $attachedIds);

新しいIDを添付します。

$message->Users()->attach($newIds);
2
Paul Spiegel

Laravelにはこのための組み込みメソッドがあります- syncWithoutDetaching

$message->Users()->syncWithoutDetaching($request->get('users'));
32
Karim

syncWithoutDetachingまたはsync([arr], false)を使用すると、コードはきれいに見えますが、のパフォーマンスはattach()より25倍遅い 。これは、各IDをチェックし、アイテムごとに個別のデータベース挿入を実行するためです。

雄弁に拡張するか、モデルクラスに新しいメソッドを作成することによって、 Paul Spiegelの回答 を基に構築することをお勧めします。

私の使用例では、多対多のピボットによってリンクされているFeedクラスとPostクラスがあります。 Feedクラスに次のメソッドを追加しました。

_public function attachUniquePosts($ids)
{
    $existing_ids = $this->posts()->whereIn('posts.id', $ids)->pluck('posts.id');
    $this->posts()->attach($ids->diff($existing_ids));
}
_
  • syncWithoutDetaching()を使用してフィードに20件の投稿を添付すると、平均0.107秒かかりました
  • attachUniquePosts()を使用してフィードに20件の投稿を添付すると、平均0.004秒かかりました
1
Kiee