使用Laravel的Fluent插入IGNORE

php mysql laravel

16357 观看

9回复

21240 作者的声誉

是否有一个快速的方法来修改生成的SQL查询Laravel的流利有一个INSERT IGNORE,而不是通常的INSERT

我正在尝试插入一个包含50个元素的数组。手动写出整个查询会使代码膨胀并使其更容易受到人为错误的影响。

作者: Nyxynyx 的来源 发布者: 2012 年 9 月 27 日

回应 (9)


-17

4101 作者的声誉

$your_array = array('column' => 'value', 'second_column' => 'value');

DB::table('your_table')->insert($your_array);

请记住,我不知道您的数据来自哪里,但您应该始终对其进行消毒。如果您有多个记录,只需循环迭代即可。

至于INSERT IGNOREINSERT在fluent库中找到方法,创建一个名为insert_ignore的新方法,与insert完全相同,只需修改即可IGNORE

作者: wesside 发布者: 27.09.2012 01:26

1

162750 作者的声誉

决定

对于这项工作,您需要创建一个新的语法,其中包含正确的字符串:

grammar.php (1)

语法是DB或者在这种情况下Database存储连接的公共属性。这不是真正的直接,但从属性的可见性,您应该能够将您的特殊语法注入数据库层。

我还建议你提出项目的问题,他们可能更好地了解如何使这些案例更灵活。


(1)这是前者,直到答复参考日期。如果你今天看到这个,你需要采用你使用的Laravel版本,例如Grammar.php for 4.0,这些类已经进入了laravel/framework

作者: hakre 发布者: 27.09.2012 01:31

13

12803 作者的声誉

在你的模型中试试这个魔法:

public static function insertIgnore($array){
    $a = new static();
    if($a->timestamps){
        $now = \Carbon\Carbon::now();
        $array['created_at'] = $now;
        $array['updated_at'] = $now;
    }
    DB::insert('INSERT IGNORE INTO '.$a->table.' ('.implode(',',array_keys($array)).
        ') values (?'.str_repeat(',?',count($array) - 1).')',array_values($array));
}

使用这样:

Shop::insertIgnore(array('name' => 'myshop'));

如果'name'属性是唯一键,这是防止first-orCrate在多用户环境中可能发生的约束违规的好方法。

作者: malhal 发布者: 24.08.2014 01:43

1

11 作者的声誉

不确定是否对任何人都有帮助,但最近我已经改编了hakre对Laravel 5的方法:

您必须更改以下3个文件才能使Insert Ignore工作:

  1. 在Builder.php(vendor / laravel / framework / src / illuminate / database / query / Builder.php)中,你必须克隆函数insert,将名称更改为insertIgnore并将语法调用函数更改为: $sql = $this->grammar->compileInsertIgnore($this, $values);)

  2. 在Grammar.php(vendor / laravel / framework / src / illuminate / database / query / grammars / Grammar.php)中,您必须克隆compileInsert函数并将其重命名为compileInsertIgnore,在此处将return更改为: return "insert ignore into $table ($columns) values $parameters";

  3. 在Connection.php(vendor / laravel / framework / src / illuminate / database / Connection.php)中,您必须简单地克隆函数insert并将其重命名为insertIgnore

现在你应该完成,连接能够识别函数insertIgnore,构建器能够指出它正确的语法,语法包含语句中的'ignore'。请问这不适用于MySQL,对于其他数据库可能不是这么顺利。

作者: Rastislav Molnar 发布者: 16.08.2016 04:09

1

49 作者的声誉

将以下方法insertIgnore添加到模型中

<?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 insertIgnore(array $attributes = [])
    {
        $model = new static($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));
        $values = $grammar->parameterize($attributes);

        $sql = "insert ignore into {$table} ({$columns}) values ({$values})";

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

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

        return $model;
    }
}

您可以使用:

App\User::insertIgnore([
    'name' => 'Marco Pedraza',
    'email' => 'mpdrza@gmail.com'
]);

它将执行的下一个查询:

insert ignore into `users` (`name`, `email`, `updated_at`, `created_at`) values (?, ?, ?, ?)

如果已启用或禁用,此方法会自动添加/删除Eloquent时间戳。

作者: Marco Pedraza 发布者: 02.11.2016 02:53

6

15910 作者的声誉

我无法像拉斯蒂斯拉夫的回答中所说的那样修补补丁。

这对我有用:

  1. 覆盖compileInsert自定义Query Grammar类中的方法,该类扩展了框架的MySqlGrammar类。

  2. 通过setQueryGrammar从数据库连接实例调用方法,使用此自定义语法类的实例。

所以,类代码是这样的:

<?php

namespace My\Namespace;

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Grammars\MySqlGrammar;

/**
 * Changes "INSERT" to "INSERT IGNORE"
 */
class CustomMySqlGrammar extends MySqlGrammar
{
    /**
     * Compile an insert statement into SQL.
     *
     * @param  \Illuminate\Database\Query\Builder  $query
     * @param  array  $values
     * @return string
     */
    public function compileInsert(Builder $query, array $values)
    {
        // Essentially we will force every insert to be treated as a batch insert which
        // simply makes creating the SQL easier for us since we can utilize the same
        // basic routine regardless of an amount of records given to us to insert.
        $table = $this->wrapTable($query->from);

        if (! is_array(reset($values))) {
            $values = [$values];
        }

        $columns = $this->columnize(array_keys(reset($values)));

        // We need to build a list of parameter place-holders of values that are bound
        // to the query. Each insert should have the exact same amount of parameter
        // bindings so we will loop through the record and parameterize them all.
        $parameters = collect($values)->map(function ($record) {
            return '('.$this->parameterize($record).')';
        })->implode(', ');

        return "insert ignore into $table ($columns) values $parameters";
    }
}

compileInsert从框架的类中复制了该方法,然后在方法内部,我只更改insertinsert ignore。其他一切都保持不变。

然后,在代码的特定位置,在应用程序(计划任务)中,我需要“插入忽略”,我简单地完成如下操作:

<?php

use DB;
use My\Namespace\CustomMySqlGrammar;

class SomeClass
{
    public function someMethod()
    {
        // Changes "INSERT" to "INSERT IGNORE"
        DB::connection()->setQueryGrammar(new CustomMySqlGrammar());

        // et cetera... for example:
        ModelClass::insert($data);
    }
}
作者: J. Bruni 发布者: 17.07.2017 06:58

0

178 作者的声誉

我最后发现这一个https://github.com/yadakhov/insert-on-duplicate-key这对我帮助很大

用户:: insertIgnore($用户); 这是我正在使用的方法,给它的行数组和返回的受影响的行

通过composer安装它:composer需要yadakhov / insert-on-duplicate-key

作者: Aammad Ullah 发布者: 10.05.2018 05:05

4

9653 作者的声誉

更新了Laravel Eloquent在2018年的答案

这也处理多个同时插入(而不是一次一个记录)。

警告:Eric的评论可能是正确的。这段代码适用于我过去的项目,但在再次使用此代码之前,我会仔细查看它并添加测试用例并调整功能,直到它始终按预期工作。它可能就像将TODO线向下移动到if支架外一样简单。

将它放在模型的类中或模型扩展的BaseModel类中:

/**
 * @see https://stackoverflow.com/a/25472319/470749
 * 
 * @param array $arrayOfArrays
 * @return bool
 */
public static function insertIgnore($arrayOfArrays) {
    $static = new static();
    $table = with(new static)->getTable(); //https://github.com/laravel/framework/issues/1436#issuecomment-28985630
    $questionMarks = '';
    $values = [];
    foreach ($arrayOfArrays as $k => $array) {
        if ($static->timestamps) {
            $now = \Carbon\Carbon::now();
            $arrayOfArrays[$k]['created_at'] = $now;
            $arrayOfArrays[$k]['updated_at'] = $now;
            if ($k > 0) {
                $questionMarks .= ',';
            }
            $questionMarks .= '(?' . str_repeat(',?', count($array) - 1) . ')';
            $values = array_merge($values, array_values($array));//TODO
        }
    }
    $query = 'INSERT IGNORE INTO ' . $table . ' (' . implode(',', array_keys($array)) . ') VALUES ' . $questionMarks;
    return DB::insert($query, $values);
}

使用这样:

Shop::insertIgnore([['name' => 'myShop'], ['name' => 'otherShop']]);

作者: Ryan 发布者: 19.07.2018 08:14

0

3069 作者的声誉

避免编写代码的选项是:https//github.com/guidocella/eloquent-insert-on-duplicate-key

我刚刚对它进行了测试 - 它有时会与我的5000个插页一起使用,有时会重复...

有了它,您将获得以下功能:

User::insertOnDuplicateKey($data);
User::insertIgnore($data);
作者: Gediminas 发布者: 15.07.2019 09:45
32x32