提问者:小点点

有效管理数据更改


我有一张叫做预订的桌子。此表包含代表特定服务预订的数据,具有许多变量。

不久前,我遇到了我当前数据结构的一个问题,即影响时间、日期或价格的任何预订更改都会影响其他相关的财务记录、日期的预订列表等。

我当时的解决方案是创建一个修改表,跟踪预订的任何更改。然后,每当预订模型被要求返回预订时,它会添加所做的修改(在“找到”()“蛋糕”回调中),并呈现预订的最新版本,类似这样(原谅油漆图):

当您要求预订模型返回预订#1234时,此方法可以正常工作。它返回预订的最新表示,包括所有修改(层叠在一起),包括包含所有修改和原始预订数据的数组,以供参考。

我的问题是,我最近意识到,我需要能够使用自定义条件查询此模型,如果其中一个条件在其中一个修改中实现,则结果将不匹配,因为模型正在搜索原始记录,而不是最终显示的记录。我查询模型以返回abc为蓝色(非灰色)的行的示例:

在该示例中,模型直接查看abc为蓝色的行的原始数据,而不返回此结果,因为蓝色值位于找到原始结果后附加的修改中。

我现在所做的是将查询放入预订模型的beforeFind()回调中,以查找与给定条件匹配的修改,并加入预订以确保任何其他条件仍然匹配。在上面的示例中,当它返回蓝色时,它将结果存储在一个数组中作为类属性,并继续使用常规的find(),但不返回该预订的ID(因为我们找到了它的最新版本)。然后在afterFind()中将它们合并在一起,重新排序等。

这是可行的,尽管我希望它更冗长一点。

在所有这些之后,我意识到在这个应用程序的其他部分,有一些模型手动加入预订表并搜索预订。所以现在我需要一种方法,能够在不影响原始数据的情况下,最好在不改变太多代码的情况下,将修改并入所有这些手动连接到MySQL中的表中。

我的想法是,我需要删除手动连接,而是创建一个模型关联。当我查询有许多预订的客户模型(将修改应用于每个预订)时,预订模型的前查找()和后查找()是否仍然运行?

我的另一个选择是通过删除修改中可能包含的任何条件,从MySQL返回比需要更多的行,然后使用PHP根据我的搜索条件过滤结果。这个选项让我有点害怕,因为如果没有这个标准,结果集可能是巨大的。。。

如何实现这种数据结构?我的主要要求仍然是,我不想更改原始预订记录,而是在顶部添加修改记录,但我需要能够通过模型查询预订(包括修改)。

我想尽可能多地将这种集成保持在幕后,这样我就不必通过我的整个应用程序来更改如下所示的查询数量:

$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's an example
            'alias' => 'Booking',
            'type' => 'LEFT',
            'conditions' => 'Booking.booking_id = Transaction.booking_id'
        )
    ),
    'conditions' => array(
        'Booking.abc' => 'blue'
    )
));

正如您所看到的,上面的查询将不包括上面我的MSPaint示例中的修改,因为它是在SQL中手动连接表的(修改集成在预订模型的beforeafterFind()回调函数中)。

在此方面的任何帮助都将不胜感激。

我知道这已经足够长了,但我想补充一点,我想跟踪这些变化而不更新原始记录的原因是财务方面不能改变,因为它会影响报告。

到目前为止,我能看到的最快和最简单的解决方案是在所有情况下直接对原始预订进行修改,除非它影响财务信息,这仍然被跟踪为修改(因为我目前不需要基于此信息进行搜索)。


共3个答案

匿名用户

听起来好像您正在尝试实现一个时态数据库。时间支持是ANSI/ISO SQL:2011标准的主要补充之一。MySQL(和大多数RDBMS一样)落后于标准。将时态数据库视为等同于CVS/SVN/Git的DBMS。

相比之下,我们使用的没有时间特征的传统数据库可以称为当前数据库。

在当前数据库中,如果您尝试实现临时支持,您可能会以多种方式使用不同的方法失败:

>

  • 一张桌子的方法。当您需要进行修改时,您会对原始记录进行更新,除非您有某种自制的触发/审核逻辑,否则历史记录将不存在。即使你有一个审计/变更日志,你也必须做一些丑陋的挖掘来重建变更历史。

    两表法。您没有进行适当的修改,而是将数据拆分为两个表,一个表包含基本/原始记录(例如预订),另一个表包含更改/修改/增量。然后,至少您保留了原始数据,但同样地,您必须编写复杂的逻辑来查看带有分层修改的原始数据。如果只想应用一些修改,情况会变得更糟。

    预先计算的结果表方法。您可以保留3个或3个以上的表:基本记录、修改,以及一个试图始终包含结果的表(保持基本修改的最新状态)。祝您在执行插入时编写触发器和过程来执行此计算,好运!如果需要更新删除,上天会帮助您。设置很脆弱,可能会中断同步,例如死锁

    结论:如果你不局限于MySQL,你应该考虑使用具有内置时态支持的DB。否则,您将重新执行控制盘。

  • 匿名用户

    与其将修改应用于原始记录,不如反过来将原始记录应用于修改?您可以修改修改表(或新表)以保存应用了修改的原始记录,并将搜索定向到那里。

    另一个想法是,如果财务数据是所有需要保存的数据,为什么不将其保存在另一个字段或表中,并在需要时引用它呢?我同意,对于长期解决方案来说,重新设计可能是最好/最聪明的方法,但我想我应该把我的想法摆在桌面上,以防它们能有所帮助。

    匿名用户

    如果在修改原始表之前使用备份表存储原始表中的数据,该怎么办?然后,您可以使用回滚函数将数据恢复到以前的状态。

    以下是我的数据库更新过程理论的流程图:http://i1371.photobucket.com/albums/ag300/joshua127/BookingFlowchartinsert_zps5c2d55f8.png

    以下是我的选择过程理论的流程图:http://i1371.photobucket.com/albums/ag300/joshua127/BookingFlowchartselect_zps702fa902.png

    希望这能有所帮助,换个角度来看。

    P. S.为了保持财务信息不变,您可以编写更新函数来计算要更新的列数(基于您的更新列名数组),并提供变量来仅保存这些列的特定值。'index'])在SQL语句中,使其动态。