Я занимаюсь разработкой приложения с использованием 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 не происходило, а триггер срабатывал как обычно.