Symfony Doctrine EntityManager 无法正确刷新

发布于 2025-01-11 10:08:02 字数 1926 浏览 0 评论 0原文

我有一个棘轮 WebSocket 服务器,其 entityManager 从后端初始化。但是,如果由于 WebSocket 服务器的 entityManager 状态与后端不同而导致前端之一发生某些更改,则新的更改不会反映在前端提供的数据中。 WebSocket 服务器。

为此,我在后端编写了一些侦听器,侦听这些实体中的更改,然后向服务器发送请求,如下所示:

public function postUpdate(Room $entity, LifecycleEventArgs $_)
{
    try {
        Loop::run(function() use ($entityName, $id) {
        $conn = yield connect('ws://localhost:8080');
        yield $conn->send(json_encode(['message' => $entityName, 'data' => ['duid' => $id]]));
        $conn->close();});
    } catch (Exception $e) {}
}

然后,我在 WebSocket 服务器中获取实体并简单地刷新它,如下所示

function onMessage(ConnectionInterface $from, $msg)
{
    try {
        $messageData = json_decode($msg);
        switch ($messageData->message) {
            case BookingSocketActions::ROOM_CHANGED_EVENT:
//                $room = $this->entityManager->getRepository('ResourcesBundle:Room')
//                                            ->find(['id' => $id]);
                $room = $this->entityManager->getRepository('ResourcesBundle:Room')
                                            ->findRoomDetailById($messageData->data->duid);
                // $this->entityManager->clear();
                $this->entityManager->refresh($room);
                break;
        }
    } catch (Exception $ex) {
        $from->send($ex);
    }
}

:奇怪的错误:WebSocket 服务器中刷新的 $entity 的状态总是落后于实体的真实变化。假设我将 $entity->name 从“1”更改为“2”。

刷新后,WebSocket 服务器上的 $entity->name 仍然为“1”。只有当我再次将其更改为其他内容(例如“3”)时,它才会更改为“2”(刷新后)。如果我将其更改为“4”,它将变为“3”,依此类推。

该事件从后端正确触发,并且在服务器上正确获取实体。只是 refresh() 仅适用于对 WebSocket 服务器的第二次请求(因此是第二次刷新),而不适用于第一个请求。

我什至尝试过类似 $entityManager->merge($entity); 但没有结果。

我使用的是 symfony 3.4、doctrine 2.7 和ratchet 0.4.3。

I have a ratchet WebSocket server, whose entityManager is initialized from the backend. However, if some changes happen from one of the front-ends since the state of the entityManager of the WebSocket server is different from the backend, the new changes are not reflected in the data that is served by the WebSocket server.

For this purpose, I wrote some listeners on the backend that listen for changes in these entities in and then send a request to the server like so:

public function postUpdate(Room $entity, LifecycleEventArgs $_)
{
    try {
        Loop::run(function() use ($entityName, $id) {
        $conn = yield connect('ws://localhost:8080');
        yield $conn->send(json_encode(['message' => $entityName, 'data' => ['duid' => $id]]));
        $conn->close();});
    } catch (Exception $e) {}
}

I then fetch the entity in the WebSocket server and simply refresh it, like so:

function onMessage(ConnectionInterface $from, $msg)
{
    try {
        $messageData = json_decode($msg);
        switch ($messageData->message) {
            case BookingSocketActions::ROOM_CHANGED_EVENT:
//                $room = $this->entityManager->getRepository('ResourcesBundle:Room')
//                                            ->find(['id' => $id]);
                $room = $this->entityManager->getRepository('ResourcesBundle:Room')
                                            ->findRoomDetailById($messageData->data->duid);
                // $this->entityManager->clear();
                $this->entityManager->refresh($room);
                break;
        }
    } catch (Exception $ex) {
        $from->send($ex);
    }
}

Now here is the strange bug: The state of the $entity that is refreshed in the WebSocket server is always one behind the real changes of the entity. Suppose I change $entity->name from "1" to "2".

After the refresh $entity->name is still "1" on the WebSocket server. Only if I change it again to sth else, e.g. "3", will it change to "2" (after the refresh). If I change it to "4", it will go to "3" and so on.

The event is firing correctly from the backend and the entity is being fetched correctly on the server. It's just that refresh() works only on a second request (and therefore a second refresh) to the WebSocket server but not on the first.

I have tried even things like $entityManager->merge($entity); but no results.

I am on symfony 3.4, doctrine 2.7, and ratchet 0.4.3.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温馨耳语 2025-01-18 10:08:02

首先可能是检测更新变化而触发的事件。

如果您postPersist,则数据库中的实体不会发生更改。它会在flush发生之前触发。

您需要在flush之后触发发送到套接字服务器的消息。

第二件事是确保entityManager 实例分离并重新加载room 实体实例。这可以

使用$this->entityManager->getUnitOfWork()->clear(Room::class);来完成

在再次查询实体之前

$this->entityManager->getUnitOfWork()->clear(Room::class);
$room = $this->entityManager
        ->getRepository('ResourcesBundle:Room')
        ->findRoomDetailById($messageData->data->duid);

The first thing may be the event that is triggered to detect the update change.

If you you postPersist the entity wont have changed in the database. It will fire before flush happens.

You need to trigger the message to the socket server after the flush.

The second thing is to make sure that the entityManager instance detach and reload the room entity instance. That can be done with

$this->entityManager->getUnitOfWork()->clear(Room::class);

right before you query the entity again

$this->entityManager->getUnitOfWork()->clear(Room::class);
$room = $this->entityManager
        ->getRepository('ResourcesBundle:Room')
        ->findRoomDetailById($messageData->data->duid);
难理解 2025-01-18 10:08:02

Doctrine 使用 身份映射

Websocket 服务器是一个守护进程,所有清理任务均由开发人员负责

使用

\Doctrine\ORM\EntityManager::find 带有 $lockMode 参数 = \Doctrine\DBAL\LockMode::NONE

调用 \Doctrine\ORM\EntityManager::find 之前的 >\Doctrine\ORM\EntityManager::clean 方法

Doctrine uses the identity map

The websocket server is a daemon and all cleanup tasks are the responsibility of the developer

Use

\Doctrine\ORM\EntityManager::find with the $lockMode argument = \Doctrine\DBAL\LockMode::NONE

OR

Call the \Doctrine\ORM\EntityManager::clean method before \Doctrine\ORM\EntityManager::find

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文