YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

Здравствуйте, не могу решить вопрос с миграцией и записью явных значений в поле id, которое по умолчанию является примарикей,
Для пример добавляю пользователя после создания таблицы и полей

Код: Выделить всё

$this->createTable('{{%user}}', [
            'id' => $this->primaryKey()->unique(),
            'username' => $this->string(160),
        ], $tableOptions);

        if ($this->db->driverName === 'sqlsrv') {
            $this->execute('SET IDENTITY_INSERT {{%user}} ON');
        }

        $model = new User();
        $model->generateAuthKey();
        $model->setPassword('12345');
        $model->generatePasswordResetToken();

        $this->insert('{{%user}}', [
            'id'                   => 1,
            'username'             => 'admin',
        ]);
По итоге вылетает ошибка: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Невозможно вставить явное значение для столбца идентификаторов в таблице "user", когда параметр IDENTITY_INSERT имеет значение OFF.
Хотя конструкция

Код: Выделить всё

if ($this->db->driverName === 'sqlsrv') {
            $this->execute('SET IDENTITY_INSERT {{%user}} ON');
        }
Выполняется, но запись произвести нельзя, а вот если включить параметр через клиента то записи проходят без проблем, с любым номером идентификатора.
Все сходится к тому что $this->execute('SET IDENTITY_INSERT {{%user}} ON'); не выполняется по факту.
Как можно решить этот вопрос?
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

Дополнено: разобрались, команда выполняется на сервере, но! как только соединения закрывается по всей видимости и происходит очистка наших настроек или что то похожее.
В итоге сейчас думаю нужно в экшен beforeSave внессти выполнение execute SET IDENTITY_INSERT {{%user}} ON
Как правильно сделать пока нет осознания, надеюсь наставите на путь истинный)
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение unknownby »

Ты создаешь темы одну за одной, и видимо даже не прогуглил вопрос, прежде чем сюда писать :D
Вот тебе пример миграции
файл m191112_173710_add_settings

Код: Выделить всё

<?php

use yii\db\Schema;
use yii\db\Migration;
use app\common\models\Settings;

class m191112_173710_add_settings extends Migration
{
    private $tableOptions = "COLLATE='utf8_general_ci' ENGINE=MyISAM";
    private $tableName;

    public function init()
    {
        $this->db = Settings::getDb();
        $this->tableName = Settings::tableName();
        parent::init();
    }

    public function safeUp()
    {
        $this->createTable($this->tableName, [
            'settings_id' => Schema::TYPE_PK,
            'settings_accordionmenu' => Schema::TYPE_SMALLINT . '(1) DEFAULT 0',
            'settings_leftmenu' => Schema::TYPE_SMALLINT . '(1) DEFAULT 0',
            'settings_lastproducts' => Schema::TYPE_INTEGER . '(11) DEFAULT NULL',
        ], $this->tableOptions);

        $this->insert($this->tableName, ['settings_id' => Settings::SETTING_DEFAULT, 'settings_accordionmenu' => 0, 'settings_leftmenu' => 1, 'settings_lastproducts' => 9]);
    }

    public function safeDown()
    {
        $this->dropTable($this->tableName);
    }
}

Файл Settings

Код: Выделить всё

<?php
namespace app\common\models;

use app\common\models\ActiveRecord as ActiveRecordExtended;

class Settings extends ActiveRecordExtended
{

    const DATABASE_NAME = 'db';
    const TABLE_NAME    = 'settings';
    const TABLE_ALIAS   = 'st';

    const SETTING_DEFAULT = 1;

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['settings_accordionmenu', 'settings_leftmenu', 'settings_lastproducts', ], 'required'],

            [['settings_accordionmenu', 'settings_leftmenu', ], 'boolean'],
            [['settings_lastproducts', ], 'integer'],
        ];
    }

}
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

'Простите, но вы о чем, я создал одну тему, и причем тут ваш пример миграции?
Речь немного о другом идет, хоть и в заголовке присутствует слово.
Я не вижу решение моего вопроса в вашем ответе, ткните носом.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение unknownby »

criminalist писал(а): 2019.12.20, 07:06 Здравствуйте, не могу решить вопрос с миграцией и записью явных значений в поле id, которое по умолчанию является примарикей,
Для пример добавляю пользователя после создания таблицы и полей
Разве тут не сказано что нужно?
Вот и решение явное в моем примере, когда выполняется $this->insert, у меня settings_id primaryKey и я записал в него константу.

Код: Выделить всё

$this->insert($this->tableName, ['settings_id' => Settings::SETTING_DEFAULT, 'settings_accordionmenu' => 0, 'settings_leftmenu' => 1, 'settings_lastproducts' => 9]);
Я предложил альтернативу для проверки. Может если сделать так же миграцию, как я, то выполнится всё хорошо и возможно никаких проблем с сервером у вас и не наблюдается.
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

В вашем случае mysql, с ним проблем нету, (вторым сообщением от меня) я так понял что в миграции нет смысла добавлять запрос, SET при любом раскладе он будет активен только одной из таблиц, это значит что нужно вместе с SQL запросом или возможно перед ним выполнять команду SET IDENTITY_INSERT ON, для того чтобы сервер позволил ввести в поле примарикей свое значение.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение yiiliveext »

Код: Выделить всё

public function init()
    {
        parent::init();
        $this->db->on(\yii\db\Connection::EVENT_BEGIN_TRANSACTION, function () {
            $this->execute('SET IDENTITY_INSERT {{%user}} ON');
        });
    }
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

yiiliveext писал(а): 2019.12.20, 16:12

Код: Выделить всё

public function init()
    {
        parent::init();
        $this->db->on(\yii\db\Connection::EVENT_BEGIN_TRANSACTION, function () {
            $this->execute('SET IDENTITY_INSERT {{%user}} ON');
        });
    }
Спасибо завтра буду пробовать. (update: не сработало)
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

Пришел к выводу что нужно запрос SET явно вставлять с запросами к API, (забыл упомянуть что это RESTAPI)
Из PHP выполняю:
$db->prepare('SET IDENTITY_INSERT ENTERPRISE ON')->execute();
$db->prepare('INSERT INTO ENTERPRISE (idd, id, shortName) VALUES (? ,? ,?)')->execute([3, 3,'Название']);
Получаю ошибку: Невозможно вставить явное значения для столбца бла бла бла.
Если выполнить такой запрос то все в порядке, запись создается.
$db->prepare('SET IDENTITY_INSERT ENTERPRISE ON INSERT INTO ENTERPRISE (idd, id, shortName) VALUES (? ,? ,?)')->execute([3, 3,'Название']);
Транзакции типа этой EVENT_BEGIN_TRANSACTION это могут осуществить?
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение yiiliveext »

Глянул на реализацию в Yii2, чтобы реализовать такой функционал в миграции, нужно отнаследоваться от \yii\db\Command, переопределить один\два метода и забиндить через контейнер. Если интересны подробности, пишите, подскажу что, где и как поменять в этом классе.
criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

Конечно интересно буду признателен, вся текущая ситуация тянется из oracle базы, уходим от одной базы к поддержки нескольких.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение yiiliveext »

Хорошо, завтра выложу код методов для переопределения, чтобы запросы миграций вида execute() работали в одном контексте в MS SQL.
Если в вашем случае все будет работать нормально, то создадим issue на гитхабе, чтобы можно добавили возможность задавать driver params в методе prepare(), на текущий момент, к сожалению, данная возможность в фреймворке не реализована.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение yiiliveext »

В ваше локальном случае все оказалось гораздо проще, поскольку объект PDO хранится в соединении в публичном свойстве, то мы можем установить атрибут драйвера динамически. Следовательно ваш код будет выглядеть так.

Код: Выделить всё

$this->createTable('{{%user}}', [
            'id' => $this->primaryKey()->unique(),
            'username' => $this->string(160),
        ], $tableOptions);

        if ($this->db->driverName === 'sqlsrv') {
            //открываем соединение если оно оказалось закрытым 
            if (!$this->db->getIsActive()) {
                $this->db->open();
            } 
            //устанавливаем атрибут драйвера если соединение открыто
            if ($this->db->getIsActive()) {
                $this->db->pdo->setAttribute(constant('PDO::SQLSRV_ATTR_DIRECT_QUERY'), true);  
            }
            $this->execute('SET IDENTITY_INSERT {{%user}} ON');
        }

        $model = new User();
        $model->generateAuthKey();
        $model->setPassword('12345');
        $model->generatePasswordResetToken();

        $this->insert('{{%user}}', [
            'id'                   => 1,
            'username'             => 'admin',
        ]);

criminalist
Сообщения: 14
Зарегистрирован: 2019.12.20, 06:58

Re: YII2 Migrate | SET IDENTITY_INSERT ON | SQL server

Сообщение criminalist »

Здравствуйте, спасибо, завтра буду проверять и отпишусь вам.
UPD: Не удержался сел проверил, работает, понедельник будет не тяжелым :D
Спасибо еще раз огромное, думаю можно закрывать тему. Надеюсь тема будет полезной не только мне.
Ответить