Итак, я смог найти решение после нескольких часов борьбы.
Оказывается, мне не нужно ни настаивать, ни сбрасывать изменения. Решение состоит в том, чтобы использовать Unit of Work для пересчета изменений в $ parent, а затем доктрина сбросит их самостоятельно. Мне также пришлось изменить способ подсчета продуктов, так как на этапе предварительной проверки изменения еще нет в базе данных, поэтому запрос не будет работать должным образом. Вот почему я считаю их вручную, обходя дерево отношений.
Вот пример кода.
public function preFlush(Room $room, PreFlushEventArgs $args)
{
$em = $args->getEntityManager();
$numOfProducts = 0;
$parent = $room->getStore()->getParent();
foreach($parent->getStores() as $store) {
foreach($store->getRooms() as $room) {
$numOfServices += count($room->getProducts());
}
}
$parent->setNumberOfProducts($numOfProducts);
$classMetadata = $em->getClassMetadata(get_class($parent));
$em->getUnitOfWork()->computeChangeSet($classMetadata, $parent);
}
Основной проблемой с несколькими потоками является переменчивость. константа ограничивает это, но так как можно выбросить мыс константы, это не является надежным.
Любой неизменный (то есть, unchangable) данные по сути ориентированы на многопотоковое исполнение - нет никакого риска для нескольких потоков, одновременно считывающих те же данные только для чтения, потому что они никогда не собираются изменяться!
Отмечание переменной как константа в C++ делает это только для чтения и таким образом ориентированным на многопотоковое исполнение.
Функция членства константы не должна изменять состояние, которое делает безопасным звонить от нескольких потоков одновременно. Однако потокобезопасность не является целью константы, и C++ обеспечивает изменяемое ключевое слово и const_cast, означающий, что константа на самом деле не гарантирует потокобезопасности и не должна полагаться с этой целью.
Функции константы не ориентированы на многопотоковое исполнение. Normaly, можно назвать методы объекта константы от различных потоков одновременно, но если Вы называете не константу и метод константы от различных потоков, Вы получаете состояние состязания. Проверьте это:
class Foo
{
size_t size_;
public:
...
size_t get_size() const
{
return size_
}
};
class Bar
{
boost::shared_ptr<Foo> foo_;
public:
//accessor
size_t get_size() const
{
size_t size = 0;
if (foo_)
size = foo_->size();
return size;
}
//modifiers
void init()
{
foo_ = new Foo;
}
void clear()
{
foo_ = boost::shared_ptr<Foo>();
}
};
Если кто-то назовет init метод и затем назовет четкие и get_size методы одновременно, то он вызовет нарушение прав доступа. Необходимо использовать идиому блокировки записи чтения. Несколько средств доступа можно назвать одновременно, и только один модификатор можно назвать одновременно. Exemple:
class Bar
{
boost::shared_ptr<Foo> foo_;
mutable tbb::spin_rw_mutex lock_;
public:
//accessor
size_t get_size() const
{
size_t size = 0;
//lock modifiers
rw_mutex_type::scoped_lock lock(mutex, false);
if (foo_)
size = foo_->size();
return size;
}
//modifiers
void init()
{
//lock accessor and modifiers
rw_mutex_type::scoped_lock lock(mutex, true);
foo_ = new Foo;
}
void clear()
{
//lock accessor and modifiers
rw_mutex_type::scoped_lock lock(mutex, true);
foo_ = boost::shared_ptr<Foo>();
}
};
tbb:: spin_rw_lock является взаимоисключающим классом от поточной обработки библиотеки блоков здания
Константа C++ позволяет неконстанту, искажающую, такую как:
Foo myVar;
const Foo* ptr1;
Foo* ptr2;
Учитывая это, константа не обеспечивает гарантий относительно неизменности Ваших данных, даже если Вы не делаете никакого кастинга или чего-нибудь для обхождения его. При доступе к myVar через ptr1 Вы не можете изменить его через ptr1 (предполагающий, что я разобрался в синтаксисе; это было намерением.) Однако это могло все еще измениться через ptr2. То, что Вы действительно хотите, является отдельной неизменной конструкцией. Это не существует в C++.