Как регистрировать изменения записи?

Я создаю приложение, в котором пользователи могут выполнять задания, которые должны быть одобрены другим пользователем. Таким образом, если утверждающий изменяет (обновляет) какие-либо данные, связанные с этой записью, мне нужно сохранить эти изменения в таблице аудита, например https://github.com/spatie/laravel-activitylog.

Каков наилучший подход? Реализовать с помощью триггера или сравнить объекты? Есть ли у Android библиотека, которая может с ним работать?

Ниже представлена ​​модель работы:

public class Operation {
    private int id;
    private String started_at;
    private int company_id;
    private int collaborator_id;
    private int approver_id;
    private int building_id;
    private String cost_center;
    private String ended_at;
    private int shift_id;
    private int service_id;
    private String invoice_number;
    private String transport_number;
    private String cod;
    private String lot;
    private int vehicle_id;
    private int carrier_id;
    private String vehicle_plate;
    private String cart_plate;
    private int amount;
    private int loose_cargo;
    private int palletized_load;
    private int gross_weight;
    private String comments;
    private int number_assistants;
    private int number_operators;
    private int number_tractors;
    private int number_samples;
    private int number_others;
}

Я пытался создать его, как показано ниже:

"CREATE TRIGGER " + OperationEntry.TRIGGER_NAME +
    " AFTER UPDATE " +
    " ON["+ OperationEntry.TABLE_NAME +"] " +
    " FOR EACH ROW " +
    " BEGIN " +
    " DECLARE changes VARCHAR(8000); " +
    " SET changes = '{'; " +
    " IF OLD. " + OperationEntry.COLUMN_ID + " <> " + " NEW. " + OperationEntry.COLUMN_ID + " THEN " +
    "SET changes = CONCAT(changes, );" +
    " END IF; " +
    " IF OLD. " + OperationEntry.COLUMN_COMPANY + " <> " + " NEW. " + OperationEntry.COLUMN_COMPANY + " THEN " +
    "SET changes = CONCAT(changes, );" +
    " END IF; " +
    " IF OLD. " + OperationEntry.COLUMN_BUILDING + " <> " + " NEW. " + OperationEntry.COLUMN_BUILDING + " THEN " +
    "SET changes = CONCAT(changes, );" +
    " END IF; " +
    " SET changes = CONCAT(changes, '}'); " +
    " END; ");
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
204
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование ПОСЛЕ ОБНОВЛЕНИЯ TRIGGER представляется подходящим и не требует дополнительного кода, кроме кода, необходимого для генерации TRIGGER.

Проблема в том, что существование TRIGGER неочевидно, но этот недостаток можно преодолеть с помощью соответствующих комментариев в коде.

ре: -

I was trying to create it as below:

"CREATE TRIGGER " + OperationEntry.TRIGGER_NAME +
    " AFTER UPDATE " +
    " ON["+ OperationEntry.TABLE_NAME +"] " +
    " FOR EACH ROW " +
    " BEGIN " +
    " DECLARE changes VARCHAR(8000); " +
    " SET changes = '{'; " +
    " IF OLD. " + OperationEntry.COLUMN_ID + " <> " + " NEW. " + OperationEntry.COLUMN_ID + " THEN " +
    "SET changes = CONCAT(changes, );" +
    " END IF; " +
    " IF OLD. " + OperationEntry.COLUMN_COMPANY + " <> " + " NEW. " + OperationEntry.COLUMN_COMPANY + " THEN " +
    "SET changes = CONCAT(changes, );" +
    " END IF; " +
    " IF OLD. " + OperationEntry.COLUMN_BUILDING + " <> " + " NEW. " + OperationEntry.COLUMN_BUILDING + " THEN " +
    "SET changes = CONCAT(changes, );" +
    " END IF; " +
    " SET changes = CONCAT(changes, '}'); " +
    " END; ");

Я не верю, что многое из вышеперечисленного сработает. В реализации SQL SQLITE нет ключевого слова DECLARE, а ключевое слово ЕСЛИ очень ограничено.

Конкатенация значений также довольно неудобна.

Я бы предложил рассмотреть следующее, основываясь на том, что вы, кажется, пытаетесь: -

-- Drop tables and triggers (allows rerunability for testing)
DROP TABLE IF EXISTS OperationEntry;
DROP TABLE IF EXISTS OperationEntryChanges;
DROP TRIGGER IF EXISTS OperationEntryTrigger;

-- Create the original/core table
CREATE TABLE IF NOT EXISTS OperationEntry (
    id INTEGER PRIMARY KEY, 
    company TEXT,   building TEXT
);
-- Create the logging table
CREATE TABLE IF NOT EXISTS OperationEntryChanges (
    oldid INTEGER, 
    newid INTEGER, 
    oldcompany TEXT, 
    newcompany TEXT, 
    oldbuilding TEXT, 
    newbuilding TEXT, 
    timestamp DEFAULT CURRENT_TIMESTAMP, -- assumes that you want some indications of when the update was made
    updatecounter DEFAULT 0 -- maybe over the top/not required may replace or compliment timestamp
    );
-- Create the logging trigger
CREATE TRIGGER OperationEntryTrigger
    AFTER UPDATE  ON OperationEntry
        BEGIN 
            INSERT INTO OperationEntryChanges 
                (oldid, newid, oldcompany, newcompany, oldbuilding, newbuilding, updatecounter) 
            VALUES
                (old.id, new.id, old.company, new.company, old.building, new.building, (SELECT count(*) + 1 FROM OperationEntryChanges)
                );
        END
;

-- Add some testing data
INSERT INTO OperationEntry (company, building) VALUES
        ('company1','Building1'),('company1','Building2'),('company1','Building3'),('company1','Building4'),
        ('company2','Building1'),('company2','Building2'),('company2','Building3'),
        ('company3','Building1'),('company3','Building2'),('company3','Building3'),('company3','Building4'),('company3','Building5')
;

-- Show the data prior to any updates
SELECT * FROM OperationEntry;
SELECT * FROM OperationEntryChanges;

-- Apply some updates
UPDATE OperationEntry SET company = company || 'A' WHERE Building = 'Building2';
UPDATE OperationEntry SET building = replace(building,'Building','Bldg') WHERE building = 'Building5';
UPDATE OperationEntry SET building = building||'X', company = company||'X' WHERE company = 'company1' AND building = 'Building3';

-- Show the data post updates
SELECT * FROM OperationEntry;
SELECT * FROM OperationEntryChanges;
-- Show the changes made
SELECT 
  datetime(timestamp),
    updatecounter,
    CASE 
      WHEN oldcompany <> newcompany AND oldbuilding <> newbuilding THEN 'Company changed from '|| oldcompany || ' to ' || newcompany || ', also Building changed from ' || oldbuilding || ' to ' || newbuilding
        WHEN oldcompany <> newcompany THEN 'Company changed from '|| oldcompany || ' to ' || newcompany 
      WHEN oldbuilding <> newbuilding THEN 'Building changed from ' || oldbuilding || ' to ' || newbuilding END AS changemade
FROM OperationEntryChanges
;

Ниже будут результаты: -

Результат 1

Основная таблица после загрузки данных: -

Результат 2

Таблица изменений/журнала после загрузки данных (т.е. пустая, так как нет обновлений)

Результат 3

Измененная основная таблица (изменения выделены)

Результат 4

Таблица журнала изменений (после всех 5 обновлений (изменено 6 значений))

![

Результат 5

Изменения, сделанные в более удобном для человека формате

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

Tarcisiofl 14.06.2019 16:12

@Tarcisiofl у вас есть доступ ко всем значениям из обновляемой строки до и после. Используя old.column_name или new.column_name (т. е. добавляя к соответствующему столбцу префикс Старый. или новый.), см. SQL в понимании SQLite — CREATE TRIGGER

MikeT 14.06.2019 23:01

Да, я знаю это! Проблема в том, что я пытаюсь сохранить все изменения данных в одном столбце, объединяя каждое изменение.

Tarcisiofl 16.06.2019 22:47

@Tarcisiofl, это должен быть новый вопрос, учитывая исходную ограниченную информацию. Однако см. обновленный ответ.

MikeT 17.06.2019 02:25

Другие вопросы по теме