web-dev-qa-db-fra.com

Laravel 5.1 Créer ou mettre à jour en double

Dans Laravel 5.1, pour l'insertion MySQL, je veux voir si l'enregistrement existe déjà et mettre à jour en double ou en créer de nouveau s'il n'en existe pas.

J'ai déjà cherché SO où les réponses étaient pour les anciennes versions laravel. Dans l'un des anciens sujets, il était dit qu'une nouvelle updateOrCreate() la méthode a été ajoutée dans le noyau l'année dernière. Mais quand j'essaye, j'obtiens l'erreur:

Integrity constraint violation: 1062 Duplicate entry '1' for key 'app_id' 

Voici la requête que j'utilise:

AppInfo::updateOrCreate(array(
    'app_id' => $postData['appId'],
    'contact_email' => $postData['contactEmail']
));

app_id est la clé étrangère unique dans cette table et je souhaite mettre à jour l'enregistrement s'il existe ou en créer un nouveau. J'ai essayé de rechercher les documents 5.1 et je n'ai pas trouvé les informations dont j'ai besoin. Quelqu'un peut-il me guider ici s'il vous plaît ...

23
Neel

Selon la définition de la méthode du modèle éloquent "updateOrCreate ()"

function updateOrCreate (tableau $ attributs, tableau $ valeurs = []) {}

il faut deux arguments ...

  1. l'un est les attributs à l'aide desquels vous souhaitez vérifier dans la base de données si l'enregistrement est présent
  2. le second est les nouvelles valeurs d'attribut que vous souhaitez créer ou mettre à jour

AppInfo::updateOrCreate(['app_id' => $postData['appId']],
                        ['contact_email' => $postData['contactEmail']]);
38
MrPandav

Je réponds à cette question car je ne trouve aucune réponse liée à ON DUPLICATE KEY UPDATE, bien que j'utilise Laravel 5.4. Si vous regardez la méthode updateOrCreate dans le code principal de Laravel, vous verrez après tout Laravel utilise 2 requêtes différentes: une pour la mise à jour et une autre pour la création. Pour cette raison, parfois vous pouvez obtenir des données en double dans la base de données. Dans certains cas, il peut être utile d'écrire ce type de requête brute:

Instruction DB :: ("INSERT INTO table_name (col_1, col_2) VALEURS (?,?) SUR LA MISE À JOUR DE LA DOUBLE CLÉ col_1 = col_1 + 1 ", ([val_1, val_2]));

J'espère que cela peut être utile pour quelqu'un.

14
Hayk

J'ai créé un package pour travailler avec l'insertion MySQL sur une clé en double.

Cela peut être utile pour d'autres:

https://packagist.org/packages/yadakhov/insert-on-duplicate-key

Exemple:

/**
 * Class User.
 */
class User extends Model
{
    use Yadakhov\InsertOnDuplicateKey;
    ...
}

// associative array must match column names
$users = [
    ['id' => 1, 'email' => '[email protected]', 'name' => 'User One'],
    ['id' => 2, 'email' => '[email protected]', 'name' => 'User Two'],
    ['id' => 3, 'email' => '[email protected]', 'name' => 'User Three'],
];

User::insertOnDuplicateKey($users);
7
Yada

Ajoutez la méthode suivante insertUpdate à votre modèle

<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

class User extends Model implements AuthenticatableContract,
                                    AuthorizableContract,
                                    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'email', 'password'];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];


    public static function insertUpdate(array $attributes = [])
    {
        $model = new static($attributes);

        $model->fill($attributes);

        if ($model->usesTimestamps()) {
            $model->updateTimestamps();
        }

        $attributes = $model->getAttributes();

        $query = $model->newBaseQueryBuilder();
        $processor = $query->getProcessor();
        $grammar = $query->getGrammar();

        $table = $grammar->wrapTable($model->getTable());
        $keyName = $model->getKeyName();
        $columns = $grammar->columnize(array_keys($attributes));
        $insertValues = $grammar->parameterize($attributes);

        $updateValues = [];

        if ($model->primaryKey !== null) {
            $updateValues[] = "{$grammar->wrap($keyName)} = LAST_INSERT_ID({$keyName})";
        }

        foreach ($attributes as $k => $v) {
            $updateValues[] = sprintf("%s = '%s'", $grammar->wrap($k), $v);
        }

        $updateValues = join(',', $updateValues);

        $sql = "insert into {$table} ({$columns}) values ({$insertValues}) on duplicate key update {$updateValues}";

        $id = $processor->processInsertGetId($query, $sql, array_values($attributes));

        $model->setAttribute($keyName, $id);

        return $model;
    }
}

Vous pouvez utiliser:

App\User::insertUpdate([
    'name' => 'Marco Pedraza',
    'email' => '[email protected]'
]);

La prochaine requête sera exécutée:

insert into `users` (`name`, `email`, `updated_at`, `created_at`) values (?, ?, ?, ?) on duplicate key update `id` = LAST_INSERT_ID(id),`name` = 'Marco Pedraza',`email` = '[email protected]',`updated_at` = '2016-11-02 01:30:05',`created_at` = '2016-11-02 01:30:05'

La méthode ajoute/supprime automatiquement les horodatages Eloquent si vous avez activé ou désactivé.

3
Marco Pedraza

Pour utiliser laravel function pdateOrCreate vous avez besoin d'auto id d'incrémentation dans votre table.

ce qu'ils font c'est

select id from your_table where your_attributes

après cela, obtenez l'identifiant d'incrémentation automatique

puis

update your_table set your_values where field_id

3
Shanka SMS

Dans mon cas, cela était dû à un simple décalage sur la clé d'incrémentation automatique de ma table de modèles.

Obtenir l'id max actuel:

SELECT max(id) from companies

Ensuite, définissez la valeur de séquence un plus haut:

select setval('companies_id_seq', 164);

éliminé l'erreur.

1
Ben Wilson