Эффективное управление изменениями данных

У меня есть таблица под названием "Заказы". Эта таблица содержит данные, представляющие бронирование, сделанное для конкретной услуги, со многими переменными.

Некоторое время назад я столкнулся с проблемой с моей текущей структурой данных, в которой любые изменения в бронировании, которые повлияли на время, даты или цены, повлияли бы на другие связанные финансовые записи, списки заказов на даты и т.д.

Мое решение в то время состояло в том, чтобы создать таблицу модификаций, которая будет отслеживать любые изменения, внесенные в бронирование. Затем, всякий раз, когда к модели бронирования было предложено вернуть заказ, оно добавило бы внесенные изменения (в обратном вызове afterFind() Cake) и представит самую последнюю версию бронирования, что-то вроде этого (извините рисунок рисования ):

enter image description here

Этот метод отлично работает, когда вы попросите модель бронирования вернуть заявку № 1234. Он возвращает самое современное представление бронирования, включая все модификации (накладываемые друг на друга), включая массив, содержащий все модификации и исходные данные бронирования для справки.

Моя проблема заключается в том, что я недавно понял, что мне нужно иметь возможность запрашивать эту модель с пользовательскими условиями, и если одно из этих условий было реализовано в одной из модификаций, результат wouldn 't, потому что модель ищет исходную запись, а не окончательно представленную запись. Пример, когда я запрашиваю модель для возврата строк, где abc - синий (не серый):

enter image description here

В этом примере модель смотрит прямо на исходные данные для строк, где abc является синим и не возвращает этот результат, потому что синее значение находится в модификации, которая прикреплена после исходные результаты найдены.

Теперь я сделал запрос в обратном вызове beforeFind() модели бронирования, чтобы просмотреть изменения, соответствующие заданным критериям, присоединившись к бронированию, чтобы убедиться, что все остальные критерии по-прежнему совпадают. Когда он возвращает синий в примере выше, он сохраняет результат в массиве как свойство класса и продолжается с регулярным find(), но исключает, что идентификатор бронирования возвращается (потому что мы нашли более современная версия). Затем он объединит их вместе, отсортирует их снова и т.д. В afterFind().

Это работает, хотя и немного более длинным, чем я надеялся.

После всего этого я понял, что в других частях этого приложения есть модели, которые вручную присоединяются к таблице заказов и ищут заказы. Итак, теперь мне нужен способ включить изменения во все эти ручные соединения прямо в таблицу в MySQL, не затрагивая исходные данные и, желательно, не меняя слишком много кода.

Мои мысли состояли в том, что мне нужно удалить ручное соединение и создать ассоциацию модели. Будут ли модели beforeFind() и afterFind() модели бронирования по-прежнему выполняться, когда я запрашиваю модель клиента, которая имеет множество заказов (для внесения изменений в каждое бронирование)?

Моим другим вариантом было вернуть больше строк из MySQL, чем необходимо, удалив любые критерии, которые могут содержаться в модификациях, а затем используйте PHP для фильтрации результатов в соответствии с моими критериями поиска. Этот вариант немного меня напугал, потому что результирующий набор может быть массивным без этих критериев...


Как я могу достичь этой структуры данных? Мои ключевые требования по-прежнему заключаются в том, что я не хочу менять оригинальную запись бронирования, вместо этого добавляю записи модификации сверху, но мне нужно иметь возможность запрашивать заказы (включая изменения) через модель.

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

$get_blue = $this->Booking->find('all', array(
    'conditions' => array(
        'Booking.abc' => 'blue'
    )
));

Я хочу иметь возможность косвенно включать любые изменения, внесенные в заказы, чтобы обновленное бронирование было возвращено в вышеуказанном запросе.

Другая проблема заключается в том, когда модель бронирования вручную привязана к поисковому запросу, например:

$get_transactions_on_blue_bookings = $this->Transaction->find('all', array(
    'joins' => array(
        array(
            'table' => 'sql_bookings_table', // non-standard Cake format, I know - it an example
            'alias' => 'Booking',
            'type' => 'LEFT',
            'conditions' => 'Booking.booking_id = Transaction.booking_id'
        )
    ),
    'conditions' => array(
        'Booking.abc' => 'blue'
    )
));

Как вы можете видеть, приведенный выше запрос не будет включать модификацию в моем примере MSPaint выше, поскольку он вручную присоединяется к таблице в SQL (интеграция модификации находится в функциях обратного вызова before и afterFind() модель).

Любая помощь по этому поводу будет принята с благодарностью.

Изменить

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

Самое быстрое и простое решение, которое я вижу до сих пор, заключается в том, чтобы применять модификации непосредственно к первоначальному бронированию во всех случаях, за исключением случаев, когда это влияет на финансовую информацию, которая по-прежнему отслеживается как модификация (потому что мне в настоящее время не требуется поиск на основе по этой информации).

Ответ 1

Похоже, вы пытаетесь реализовать

Ответ 2

Вместо того, чтобы применять изменения к исходной записи, что делать, если вы сделали обратное и применили оригинальную запись к изменениям? Вы можете изменить таблицу модификаций (или новую таблицу), чтобы сохранить исходную запись с внесенными в нее изменениями и направить туда свои поиски.

Другая мысль состоит в том, что если финансовые данные - это все, что необходимо сохранить, почему бы не сохранить их в другом поле или таблице и не ссылаться на нее, когда она вам нужна? Я согласен с тем, что перепроектирование, вероятно, является лучшим/самым умным подходом для долгосрочного решения, но я решил, что я поместил свои идеи в таблицу, если они могут помочь.

Ответ 3

Что делать, если вы использовали резервную таблицу для хранения данных из исходной таблицы перед изменением исходной таблицы? вы можете использовать функцию отката для восстановления данных в предыдущем состоянии.

Вот блок-схема моего процесса обновления базы данных theroy: http://i1371.photobucket.com/albums/ag300/joshua127/BookingFlowchartinsert_zps5c2d55f8.png

Вот блок-схема моего процесса выбора theroy: http://i1371.photobucket.com/albums/ag300/joshua127/BookingFlowchartselect_zps702fa902.png

Надеюсь, это поможет, просто еще один способ взглянуть на него.

P.S. Чтобы сохранить финансовую информацию без изменений, вы можете написать свои функции обновления, чтобы подсчитать количество столбцов, которые нужно обновить (на основе вашего массива обновлений имен столбцов) и предоставить переменные для хранения определенных значений только для этих столбцов. вы можете ссылаться на индексы массива ($ array ['index']) в выражении SQL, чтобы сделать его динамическим.

Ответ 4

Мне кажется, вам нужна история истории, чтобы вы могли узнать, что произойдет за это время.

Я обычно достигаю такого подхода, создавая параллельную таблицу, называемую исходным добавлением _history к ней. Bookings_history в вашем случае. Структура будет похожа на оригинал, но добавляет столбцы:

a) timestamp, которые сохраняются, когда произошла модификация

b) id, чтобы определить строку в исходной таблице

Будет создан уникальный индекс для этих двух столбцов.

Каждый раз, когда происходит изменение, перед применением модификации вы копируете исходную строку в таблицу истории. Затем вы применяете модификацию в исходной таблице. Таким образом, таблица истории работает как стек, в котором вы сохраняете моментальные копии исходных данных.

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

Надеюсь, это поможет.

Ответ 5

Из ответов, которые вы собрали, уже достаточно ясно видно, что все, что вы делаете, потребует некоторой или более редизайна.

Одно из решений, которые я пока не вижу, и что я использовал в прошлом для решения таких проблем (т.е. заказы, которые были изменены) - это сохранить все в одной таблице и использовать поле (ы), чтобы различать их.

Вы можете изменить таблицу bookings, чтобы добавить добавочное целое число для заказа (т.е. version_number) и поле is_latest. Таким образом вы можете запросить с помощью is_latest=true, чтобы получить текущую запись и ее version_number. Если оно равно 0, изменений не было, если оно > 0, то есть изменения (это число будет равно числу изменений). Вы сможете "перемотать" или "переиграть" историю, если перейти от последней версии к 0 или наоборот, и каждый раз, когда у вас будет полная запись, которую ваше приложение понимает без изменений.

Если индексируется is_latest, скорость запросов (почти) будет равна скорости загрузки исходной таблицы, и, конечно, вы можете добавить больше логических значений, например is_original, если вам нужно получить первоначальное бронирование много раз.

Это имеет то преимущество, что, скорее всего, вам потребуется изменить только модель Booking, но это будет зависеть от вашего кода.

EDIT: Я считаю, что этот подход будет наиболее совместим с вашими требованиями в отношении отчетности и финансовой записи, так как вы всегда будете иметь исходную запись (версия 0).