Yii2插入忽略/插入重复项

时间:2015-01-30 15:44:44

标签: php mysql yii2

我对Yii2来说相对较新,到目前为止,我非常喜欢它。 然而,我发现了与数据库插入相关的问题,更具体地说是MySQL。

问题很简单:我将值插入表中,我需要检查重复项,所以我的想法是使用 INSERT IGNORE ON DUPLICATE KEY UPDATE

这是我用于插入的代码:

$db->createCommand()
->insert('sdg_fb_apps', [
'fb_id' => $app->id,
'page_id' => $page_id,
'name' => $app->name,
'app_id' => $app_id,
'app_name' => $app_name,
])
->execute();

我必须使用唯一键:id和app_id,如果我运行此代码,我很明显会被Yii抛出异常。

有这个扩展名,但据我所知只适用于Yii 1.0:http://www.yiiframework.com/extension/rdbcommand

我还在GitHub上找到了这个代码片段,如下所示:

class MyQueryBuilder extends yii\db\mysql\QueryBuilder
{
    public function batchInsert($table, $columns, $rows)
    {
        $sql = parent::batchInsert($table, $columns, $rows);
        $sql .= 'ON DUPLICATE KEY UPDATE';
        return $sql;
    }
}

我不了解如何扩展Querybuilder,是否可以通过组件?

我通过查询来查看app_id之前是否已经在数据库中,然后只有在它们不存在的情况下插入才能完成我想要的工作,但是这应该必须扩展到巨大的数字和这种方法可能不是最好的。

任何指导将不胜感激,提前谢谢。

5 个答案:

答案 0 :(得分:1)

一年多过去了,我在这里发现了这个未解决的问题。我觉得这有一些牵引力,所以最好添加一个合适的答案。

在Yii2中,想法是找到模型,检查是否存在然后保存。该框架将自动更新或插入,这是我从Viewlike.us - Yii2 Insert and Ignore duplicates得到的一个片段:

$model = YourModel::findOne(ID); // findOne() searches for the table key, you can use find()->where('=', 'column', 'name')->one(); to identify the model.

if(!$model):
    $model = new YourModel();
endif;

$model->column_1 = 'text';
$model->column_2 = 123; // integer
$model->save();

答案 1 :(得分:0)

有许多事情需要考虑,可能有更好的方法来完成任务,但最直接的答案(基于您提供的信息)将扩展QueryBuilder。

使用适当的命名空间简单地创建一个app组件,并如上所示扩展QueryBuilder。

如果您使用ActiveRecord模型而不是直接执行sql命令,那么可以使用其他方法来实现预期目标。

答案 2 :(得分:0)

您的问题的关键是方法 $ db-> createCommand()。在内部,它使用 $ commandClass 公共属性,默认情况下为 yii \ db \ Command 。您可以在应用程序配置中更改它以覆盖命令方法,如 batchInsert()等。以下是我的应用程序中的示例:

ScrollReveal is not defined

您的命令类可能如下所示:

'db' => [
    'class' => 'yii\db\Connection',
    'charset' => 'utf8',
    'enableSchemaCache' => YII_ENV_PROD,
    'commandClass' => 'app\db\MyCommand'
],

但我宁愿引入单独的方法,例如 batchInsertUpdate()或其他东西。

答案 3 :(得分:0)

自Yii 2.0.14起,有一个upsert()方法可用于此。

$db->createCommand()
    ->upsert(
        'sdg_fb_apps',
        [
            'fb_id' => $app->id,
            'page_id' => $page_id,
            'name' => $app->name,
            'app_id' => $app_id,
            'app_name' => $app_name,
        ],
        false
    )
    ->execute();

答案 4 :(得分:0)

对于 Yii 1(Yii 2 应该类似)我继承了 CActiveRecord 然后我将插入函数复制到 insertIgnoreDuplicates, 我在 createInsertCommand 调用后做了以下更改:

/**
     * Inserts ignore duplicates a row into the table based on this active record attributes.
     * If the table's primary key is auto-incremental and is null before insertion,
     * it will be populated with the actual value after insertion.
     * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
     * After the record is inserted to DB successfully, its {@link isNewRecord} property will be set false,
     * and its {@link scenario} property will be set to be 'update'.
     * @param array $attributes list of attributes that need to be saved. Defaults to null,
     * meaning all attributes that are loaded from DB will be saved.
     * @return boolean whether the attributes are valid and the record is inserted successfully.
     * @throws CDbException if the record is not new
     */
    public function insertIgnoreDuplicates($attributes = null)
    {
        try {
            return $this->insert($attributes);
        } catch (CDbException $ex) {
            if ($ex->code == 23000) // ignore duplicated key 
            {
            } else {
                throw $ex;
            }
        }
    }

用法:

$x = new record();
$x->attr1  = 'val';
$x->insertIgnoreDuplicates();
相关问题