php - doctrine中文 - doctrine教學




Doctrine2如何在回滾後處理更新實體?(“EntityManager關閉”) (2)

在這個特定的例子中,您正在向Report添加規範 那麼你能這樣嗎?

$entityManager->clear("Your\Bundle\Entity\Specification");

然後按照你的建議去做:

// Store error info:
$report->setState('error');
$entityManager->persist($report);
$entityManager->flush(); // all hell breaks loose in here

此外,我認為persist對象與分配的ID是無效的。 ( catch分支中的$report對象)

我正在嘗試在事務內部進行一些處理,並保存有關潛在故障的信息,如下所示:

$conn->beginTransaction();
try
{
    $report = $reportRepository->find($id);
    $user = $report->getUser();

    $specification = new Specification();
    $entityManager->persist($specification);

    throw new ProcessingWentWrongException();

    $entityManager->flush();
    $conn->commit();
}
catch(ProcessingWentWrongException $e)
{
    $conn->rollback();

    // Store error info:
    $report->setState('error');
    $entityManager->persist($report);
    $entityManager->flush(); // all hell breaks loose in here
}

這看起來像是一個非常常見的模式,但是Doctrine很難做到這一點:

  1. flushcatch{}部分將嘗試堅持$report$specification對象,這顯然是錯誤的,所以我可以clear entityManager ,但是然後...

  2. 如果我clearentityManager$report不再由它來管理,所以我需要調用$em->merge($report)來使其再次被管理。 顯然$user將保持非託管,所以教義將執行一個insert或抱怨persist cascade 。 所以我可以merge()整個圖(它吸)或close entityManager,但是...

  3. 如果我closeentityManager我只能通過$repo->find($id);來重新獲取report實例$repo->find($id); - 但我不想這樣做,這是愚蠢的。

我錯過了什麼? 有沒有其他方法可以達到上述結果? 我覺得教義讓事情變得簡單。


簡短的回答

使用兩個實體管理者。 一個用於潛在的不安全操作,另一個用於記錄/報告。

長答案

通常,您不能確保錯誤不會發生(在刷新到數據庫之前,某些錯誤不會發生)。 一旦發生,實體管理者就會關閉。

這是我做的(摘自config.yml):

doctrine:
    orm:
        default_entity_manager: 'default'
        entity_managers:
            default:
                mappings: { ... }
            logging:
                mappings: { ... }

對於正常的操作,我使用默認的實體管理器,不需要修改代碼。

對於元操作(例如記錄批處理導入的進度或結果等),我明確地獲取'logging'管理器並將其用於創建/更新日誌記錄/報告實體(僅用於這些實體)。