Symfony Doctrine EntityManager 无法正确刷新
我有一个棘轮 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先可能是检测更新变化而触发的事件。
如果您
postPersist
,则数据库中的实体不会发生更改。它会在flush
发生之前触发。您需要在
flush
之后触发发送到套接字服务器的消息。第二件事是确保entityManager 实例分离并重新加载
room
实体实例。这可以使用
$this->entityManager->getUnitOfWork()->clear(Room::class);
来完成在再次查询实体之前
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 beforeflush
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
Doctrine 使用 身份映射
Websocket 服务器是一个守护进程,所有清理任务均由开发人员负责
使用
\Doctrine\ORM\EntityManager::find
带有$lockMode
参数 =\Doctrine\DBAL\LockMode::NONE
或
调用
方法\Doctrine\ORM\EntityManager::find
之前的 >\Doctrine\ORM\EntityManager::cleanDoctrine 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