Есть ли способ заставить триггеры SQLServer работать с запросами Eloquent? - PullRequest
2 голосов
/ 30 апреля 2019

Я занимаюсь разработкой приложения с использованием Laravel 5.5 и SQLServer.Меня попросили создать таблицу «History», в которой мы будем отслеживать действия UPDATE.Например, если мы обновляем описание заявки, мы вставляем идентификатор, поле, предыдущее значение и новое значение этого поля.

Обычно это делается с помощью триггеров в базе данных, поэтому я настроил триггер after_update.

Теперь мой триггер работает, но не тогда, когда запросы пишутся с помощью Eloquent.Если я использую объект PDO того же соединения, что и мои Модели, триггеры работают.Если я пишу запрос в интерфейсе базы данных, используя то же соединение, они работают.Но если я напишу тот же запрос с Eloquent, поле будет обновлено, но триггеры не сработают.

Я знаю, что Наблюдатели существуют, чтобы действовать как триггеры, и я настроил их на то же самое.Но я не понимаю, почему триггеры не работают, и мне интересно, является ли это нормальным поведением или мои настройки каким-то образом неисправны.

Мое соединение в файле database.php выглядит следующим образом (со значениями по умолчанию, которые я здесь удалил):

'uti' => [
            'driver'   => 'sqlsrv',
            'host'     => env('DB_HOST'),
            'database' => env('DB_DATABASE'),
            'username' => env('DB_USERNAME'),
            'password' => env('DB_PASSWORD'),
            'prefix'   => '',
            'charset'   => 'iso-8859-1',
            'characterset' => 'iso-8859-1',
            'collation' => 'French_CI_AS',
        ],

Код, с которым работает триггер:

use Illuminate\Support\Facades\DB;

$oPdo = DB::connection('uti')->getPdo();
$sQuery = $oPdo->prepare("
            UPDATE TICKET SET
            T_DESC = :sDesc
            WHERE T_CODE = :iCode");
$sQuery->execute([':sDesc' => $sDesc, ':iCode' => $code]);

Код, с которым он не работает:

$oTicket = Ticket::find($code);
        $oTicket->T_DESC = $sDesc;
        $oTicket->save();

Триггер выглядит примерно так (с большим количеством 'IF UPDATE ()' для каждого поля таблицы TICKET):

USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[after_update_ticket]
ON [dbo].[TICKET] 
AFTER UPDATE
AS
BEGIN -- begin trigger
SET NOCOUNT ON

IF EXISTS (SELECT * FROM INSERTED) And EXISTS(SELECT * FROM DELETED)
-- Is an update --
BEGIN -- begin if update
    DECLARE @user int = 1;
        IF NOT UPDATE (MODIFICATION_DATE) AND NOT UPDATE (MODIFICATION_USER)
            BEGIN -- begin if not update
-- If database connection user is letter + number, user id = number
            IF (ISNUMERIC(SUBSTRING(USER_NAME(USER_ID (CURRENT_USER)),2, LEN(USER_NAME(USER_ID (CURRENT_USER)))))=1)
                BEGIN
                    SET @user = SUBSTRING(USER_NAME(USER_ID (CURRENT_USER)),2, LEN(USER_NAME(USER_ID (CURRENT_USER))));
                END

            -- Update MODIFICATION date and user --

                UPDATE [TICKET] SET 
                MODIFICATION_DATE = CURRENT_TIMESTAMP, 
                MODIFICATION_USER = @user
                WHERE CODE = (SELECT T_CODE FROM inserted)


            -- History trigger --
            IF UPDATE(T_DESC)
                BEGIN
                INSERT INTO HISTORIQUE 
                (H_DATE,H_TABLE,H_FIELD,H_BEFORE,H_AFTER,H_CODE,CREATION_USER,CREATION_DATE) 
                VALUES 
                (CURRENT_TIMESTAMP,'TICKET','T_DESC',(SELECT T_DESC FROM deleted),(SELECT T_DESC FROM inserted),(SELECT T_CODE FROM inserted),@user,CURRENT_TIMESTAMP)
                END
END -- end if no update

END -- end if update

END -- end trigger

Я пытался исследовать триггеры, laravel и eloquent, но просмотр документов и несколько вопросов о стековом потоке не дал мне информации об ожидаемом поведении триггеров с Eloquent.Я обнаружил, что некоторые люди создали их вручную с помощью миграций, поэтому я предполагаю, что они должны работать, но я не смог найти информацию, которая бы мне помогла.

Спасибо.

ОБНОВЛЕНИЕ

Eloquent обрабатывает автоматический метод обновления для create_at и updated_at одновременно собновление на поле.(здесь updated_at определен как MODIFICATION_DATE).В результате к базе данных отправляется только один запрос:

update [TICKET] set [T_DESC] = 'desc with eloquent', [MODIFICATION_DATE] = '2019-05-02 08:45:53' where [T_CODE] = 16770

Из-за моего оператора IF NOT UPDATE (MODIFICATION_DATE) в триггере это заблокировало его запуск.

Я установил public $timestamps = false; в своей модели Ticket, чтобы автоматическое обновление Laravel на updated_at не происходило, а триггер срабатывал как обычно.

...