添加 1:1 关系
添加 1:1 关系。
本文档介绍如何在两个类之间创建一对一关系。更多详细内容请参考 iTop 官方文档。
概述
iTop 没有专门的 1:1 关系字段类型,但可以通过以下方式实现:
- 此方案仅为可选方案之一
- 关系只能在一边编辑
- 关系必须从两边可见
两个类之间的 1:1 关系
以 Person 和 CompanyCar 为例:一个人只能有一辆公司车,一辆车只能分配给一个人。
声明两个外部键
<field id="companycar_id" xsi:type="AttributeExternalKey" _delta="define">
<filter><![CDATA[SELECT CompanyCar AS cc WHERE cc.person_id = 0]]></filter>
<dependencies/>
<sql>companycar_id</sql>
<target_class>CompanyCar</target_class>
<is_null_allowed>true</is_null_allowed>
<on_target_delete>DEL_MANUAL</on_target_delete>
<allow_target_creation>true</allow_target_creation>
</field>
<field id="person_id" xsi:type="AttributeExternalKey" _delta="define">
<filter/>
<dependencies/>
<sql>person_id</sql>
<target_class>Person</target_class>
<is_null_allowed>true</is_null_allowed>
<on_target_delete>DEL_MANUAL</on_target_delete>
<allow_target_creation>false</allow_target_creation>
</field>
强制键同步
使用事件监听器在写入后同步两个外部键:
<event_listeners>
<event_listener id="AfterWriteOneToOneRelationKeys" _delta="define">
<event>EVENT_DB_AFTER_WRITE</event>
<filters>
<filter>Person</filter>
<filter>CompanyCar</filter>
</filters>
<rank>0</rank>
<code><![CDATA[function(Combodo\iTop\Service\Events\EventData $oEventData)
{
$sCurrentClass = 'Person';
$sKeyToCurrent = 'person_id';
$sRemoteClass = 'CompanyCar';
$sKeyToRemote = 'companycar_id';
$oObject = $oEventData->Get('object');
if (get_class($oObject) == $sCurrentClass) {
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
if (($oEventData->Get('is_new') || array_key_exists($sKeyToRemote, $aChanges))
&& ($oObject->Get($sKeyToRemote) > 0)) {
$oNewRemote = MetaModel::GetObject($sRemoteClass, $oObject->Get($sKeyToRemote), false, true);
if ($oNewRemote) {
$oNewRemote->Set($sKeyToCurrent, $oObject->GetKey());
$oNewRemote->DBUpdate();
}
}
if (!$oEventData->Get('is_new') && array_key_exists($sKeyToRemote, $aChanges)
&& ($aChanges[$sKeyToRemote] > 0)) {
$oOldRemote = MetaModel::GetObject($sRemoteClass, $aChanges[$sKeyToRemote], false, true);
if ($oOldRemote) {
$oOldRemote->Set($sKeyToCurrent, 0);
$oOldRemote->DBUpdate();
}
}
}
}]]></code>
</event_listener>
<event_listener id="OnDeleteOneToOneRelationKeys" _delta="define">
<event>EVENT_DB_BEFORE_DELETE</event>
<filters>
<filter>Person</filter>
<filter>CompanyCar</filter>
</filters>
<rank>0</rank>
<code><![CDATA[function(Combodo\iTop\Service\Events\EventData $oEventData)
{
$sCurrentClass = 'Person';
$sKeyToCurrent = 'person_id';
$sRemoteClass = 'CompanyCar';
$sKeyToRemote = 'companycar_id';
$oObject = $oEventData->Get('object');
if ((get_class($oObject) == $sCurrentClass) && ($oObject->Get($sKeyToRemote) > 0)) {
$oOldRemote = MetaModel::GetObject($sRemoteClass, $oObject->Get($sKeyToRemote), false, true);
if ($oOldRemote) {
$oOldRemote->Set($sKeyToCurrent, 0);
$oOldRemote->DBUpdate();
}
}
}]]></code>
</event_listener>
</event_listeners>
防止在一边编辑
为避免无限更新循环,锁定一边的编辑:
public function evtSetInitialAttributeFlags(Combodo\iTop\Service\Events\EventData $oEventData)
{
$this->ForceInitialAttributeFlags('person_id', OPT_ATT_HIDDEN);
}
public function evtSetAttributeFlags(Combodo\iTop\Service\Events\EventData $oEventData)
{
$this->ForceAttributeFlags('person_id', OPT_ATT_READONLY);
}
允许"抢占"
若要将已分配的车辆重新分配给另一个驾驶员:
- 修改过滤器允许抢占
- 在更新前一个驾驶员时,需要避免无限循环
原文:https://www.itophub.io/wiki/page?id=3_2_0:customization:one-to-one-relation
版本:3_2_0/customization/one-to-one-relation.txt · Last modified: 2025/05/19 16:10 by 127.0.0.1