处理 Propel 对象的计算字段的最佳方式是什么?
假设我有一个对象“Customer”,它有一个相应的表“customers”,并且每一列对应于我的对象的一个属性。我想做的是:在视图 A 上使用它时,向我的对象添加一个计算属性“已完成订单数”,但不在视图 B 和 C 上使用它。
计算出的属性是通过 ID 链接到我的“客户”对象的“订单”对象的 COUNT() 个。
我现在可以做的是首先选择所有 Customer 对象,然后迭代计算所有这些对象的 Orders,但我认为在单个查询中执行此操作会提高性能。但我无法正确“水合”我的 Propel 对象,因为它不包含计算字段的定义。
你会如何处理它?
有几种选择。首先,是在数据库中创建一个视图来为您进行计数,类似于我的答案here https://stackoverflow.com/questions/234785/#235267。我为当前正在从事的 Symfony 项目执行此操作,其中给定表的只读属性实际上比表本身宽得多。这是我的建议,因为分组列(max()、count() 等)无论如何都是只读的。
其他选项是将此功能实际构建到您的模型中。您绝对可以自己进行补水,但有点复杂。这是粗略的步骤
- 将列添加到您的Table类作为受保护的数据成员。
- 为这些列编写适当的 getter 和 setter
- 覆盖水合物方法并在其中使用其他查询的数据填充新列。确保在第一行调用parent::Hydrate()
但是,这并不比您已经谈论的好多少。你仍然需要N+ 1 个查询来检索单个记录集。但是,您可以在步骤#3 中发挥创意,以便N是计算的列数,而不是返回的行数。
另一种选择是在您的系统上创建自定义选择方法Table同侪阶级。
- 执行上面的步骤 1 和 2。
- 编写您将通过 Propel::getConnection() 过程手动查询的自定义 SQL。
- 通过迭代结果集手动创建数据集,并在此时处理自定义水合,以免在 doSelect 进程使用时破坏水合。
这是此方法的一个示例
<?php
class TablePeer extends BaseTablePeer
{
public static function selectWithCalculatedColumns()
{
// Do our custom selection, still using propel's column data constants
$sql = "
SELECT " . implode( ', ', self::getFieldNames( BasePeer::TYPE_COLNAME ) ) . "
, count(" . JoinedTablePeer::ID . ") AS calc_col
FROM " . self::TABLE_NAME . "
LEFT JOIN " . JoinedTablePeer::TABLE_NAME . "
ON " . JoinedTablePeer::ID . " = " . self::FKEY_COLUMN
;
// Get the result set
$conn = Propel::getConnection();
$stmt = $conn->prepareStatement( $sql );
$rs = $stmt->executeQuery( array(), ResultSet::FETCHMODE_NUM );
// Create an empty rowset
$rowset = array();
// Iterate over the result set
while ( $rs->next() )
{
// Create each row individually
$row = new Table();
$startcol = $row->hydrate( $rs );
// Use our custom setter to populate the new column
$row->setCalcCol( $row->get( $startcol ) );
$rowset[] = $row;
}
return $rowset;
}
}
您的问题可能还有其他解决方案,但超出了我的知识范围。祝你好运!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)