持久化统计 n:n
持久化统计 n:n。
本文档介绍如何在 iTop 中持久化存储 n:n 关系的计数,例如在团队上统计成员数量。更多详细内容请参考 iTop 官方文档。
前提条件
目标
在对象 A 的详情中显示通过多对多关系链接到对象 A 的对象 B 的数量。本示例使用 Team 与 Person 的关系,在 Team 上存储团队成员数量。
lnkPersonToTeam类有person_id和team_id外键,存储多对多关系Team上有persons_list字段,提供链接到该团队的人员列表Person上有teams_list字段,提供链接到该人员的团队列表- 需要在
Team类上创建persons_count字段,存储团队中的人员数量
需要支持:
- 在 A 对象列表中查看此计数
- 通过 OQL 查询轻松查找具有超过 10 个相关 B 对象的 A 对象
iTop 3.1.1+ 方式
使用事件机制,订阅特定事件并在事件触发时执行方法。
计算成员
public function CountMembers(Combodo\iTop\Service\Events\EventData $oEventData)
{
$oLnkSet = $this->Get('persons_list');
if (is_object($oLnkSet)) {
$this->Set('persons_count', $oLnkSet->Count());
$this->DBUpdate();
}
}
处理字段
<class id="Team" _delta="must_exist">
<fields>
<field id="persons_list" _delta="must_exist">
<with_php_computation>true</with_php_computation>
</field>
<field id="persons_count" xsi:type="AttributeInteger" _delta="define">
<sql>persons_count</sql>
<default_value>0</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
</fields>
</class>
订阅事件
<class id="Team" _delta="must_exist">
<event_listeners>
<event_listener id="CountMembers" _delta="define">
<event>EVENT_DB_LINKS_CHANGED</event>
<callback>CountMembers</callback>
<rank>0</rank>
</event_listener>
</event_listeners>
</class>
3.1.1 之前的方式
这种方式更复杂。需要确定何时计算什么。
在 Team 上
添加计数器字段:
<class id="Team" _delta="must_exist">
<fields>
<field id="persons_count" xsi:type="AttributeInteger" _delta="define">
<sql>persons_count</sql>
<default_value>0</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
</fields>
</class>
创建函数:
public function ComputeValues()
{
$this->ComputePersons();
}
public function ComputePersons($iDelta=0)
{
if ($iDelta==0)
{
$oSet = $this->Get('persons_list');
$i = $oSet->count();
}
else
{
$i = $this->Get('persons_count') + $iDelta;
}
$this->Set('persons_count', $i);
return $i;
}
在链接对象上
创建
- 要求 Team 重新计算其计数
修改
需要考虑所有可能的变更:
- 团队变更:旧团队减一,新团队加一
删除
- 要求 Team 从其计数中减一
public function UpdateRemote($iTeamId, $iDelta = 0)
{
$oTeam = MetaModel::GetObject('Team', $aChanges['Team'], false, true);
if (is_object($oTeam ))
{
$oTeam->ComputePersons($iDelta);
$oTeam->DBUpdate();
}
}
protected function AfterInsert()
{
$this->UpdateRemote($this->Get('team_id'), 1);
}
protected function AfterUpdate()
{
$aChanges = $this->ListPreviousValuesForUpdatedAttributes();
if (array_key_exists('team_id', $aChanges))
{
$this->UpdateRemote($aChanges['team_id'], -1);
$this->UpdateRemote($this->Get('team_id'), 1);
}
}
protected function AfterDelete()
{
$this->UpdateRemote($this->Get('team_id'), -1);
}
在 Person 上
- 人员创建 → 通过关联链接的创建处理
- 人员删除 → 通过关联链接的级联删除处理
无需额外操作!
通用 UpdateCounter 函数
/**
* @param $id 远程对象的 ID
* @param $sClass 远程对象的类名
* @param $sCounterCode 远程类上存储关系计数的属性代码
* @param $iDelta 添加到计数器的数值(可为负数)
*/
public function UpdateCounter($id, $sClass, $sCounterCode, $iDelta=0)
{
if (in_array($sCounterCode,MetaModel::GetAttributesList($sClass)))
{
$oObject = MetaModel::GetObject($sClass, $id, false, true);
if (is_object($oObject ) && ($iDelta!=0))
{
$i = $oObject->Get($sCounterCode) + $iDelta;
$oObject->Set($sCounterCode, $i);
$oObject->DBUpdate();
}
}
}
原文:https://www.itophub.io/wiki/page?id=3_2_0:customization:count-linkset-indirect
版本:3_2_0/customization/count-linkset-indirect.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1