Проблема с Propel ORM - PullRequest
       1

Проблема с Propel ORM

2 голосов
/ 09 ноября 2010

Я использую Propel ORM в своей разработке, и у меня есть эта проблема:

$mo = new Category();
$mo->setId(7); // This Id exists
$mo->setDescription('New description!');
$mo->save(); //it should update!

Ну, это не обновляет значения.Выдает исключение и говорит, что я не могу вставить дубликат ключа.Есть ли способ обойти это?

Надеюсь, кто-то может помочь, Дэвид

[РЕДАКТИРОВАТЬ]

Я знаю, что я могу сделать это:

$mo = CategoryQuery::create()
             ->findByPk(7)
             ->setDescription("something")
             ->save();

Я знаю, что это работает, но из-за особых проблем моего проекта я не могу этого сделать.Так вот почему вопрос.

Еще раз спасибо!

Ответы [ 4 ]

3 голосов
/ 09 октября 2012

Это похоже на старую ветку. Вот обновленный ответ, о котором я хотел бы упомянуть

$q = array(1,2,3,4);
$rp = RolesPermissionsQuery::create()->filterById($roleId)->findOneOrCreate();
$rp->setRolesId($roleId);
$rp->setPermissions(serialize($q));
$rp->save();

В приведенном выше коде propel создаст новую строку или обновит существующую строку в зависимости от условия. Надеюсь, это кому-нибудь поможет.

1 голос
/ 10 ноября 2010

«Подделка» существующего объекта

Propel выбирает между вставкой и обновлением на основе результата вызова isNew() для объекта, который вы хотите сохранить (см. Вашу функцию BaseCategory::save(): $isInsert = $this->isNew();). Поэтому вы можете обмануть его, думая, что это существующий объект, изменив это свойство самостоятельно: $mo->setNew(false);. isNew() и setNew() определены в BaseObject классе .

В целом, может быть, не очень хорошая идея работать с частично гидратированными объектами (что вы, похоже, делаете здесь: вы создаете объект, но затем не заполняете все свойства их фактической базой данных ценности). Некоторые варианты поведения или ваш собственный код могут зависеть от двух свойств объекта и приводить к неверным результатам. Упрощенный пример: если у вас есть автоматически сгенерированное поле nameAndDescription, которое вы задаете для конкатенации полей name и description при сохранении (путем расширения объекта Propel с помощью новых preInsert() и preUpdate() ловит), это не будет делать то, что вы ожидаете, если вы обновите свой объект, как вы делаете это здесь. Но это единственное предупреждение, которое я знаю, и, вероятно, это ситуация, которую вы держите под контролем.

Обновление полей без создания объекта

Если вы хотите обновить только некоторые поля и, возможно, даже для нескольких объектов (например: для всех Order объектов с executionDate до сегодняшнего дня, установите status в "archived"), вы можете сделать позвоните BasePeer::doUpdate() сами. Первым аргументом является выбранный вами объект Criteria: все Order объектов с executionDate до сегодняшнего дня. Второй аргумент также является объектом Criteria, но он используется для хранения новых значений: от status до "archived". Это должно выглядеть так (не проверено):

// This probably also works with a Query object
$selectCriteria = new Criteria(OrderPeer::DATABASE_NAME);
$selectCriteria->add(OrderPeer::EXECUTION_DATE, time(), Criteria::LESS_THAN);

// And this too, it's just used as a simple hash table
$valueCriteria = new Criteria(OrderPeer::DATABASE_NAME);
$valueCriteria->add(OrderPeer::STATUS, "archived");

$con = Propel::getConnection(OrderPeer::DATABASE_NAME, Propel::CONNECTION_WRITE);
BasePeer::doUpdate($selectCriteria, $valueCriteria, $con);

Этот метод, конечно, не будет выполнять никаких хуков preUpdate() или postUpdate(), которые вы определили в коде PHP, так как сгенерированные объекты полностью обойдены. Так что используйте его только тогда, когда это абсолютно необходимо (из соображений производительности?), И вы знаете, что вокруг нет других "устаревших" объектов.

0 голосов
/ 12 марта 2015

Используйте Find One или Create, чтобы найти или создать объект

$ mo = CategoryQuery :: create () -> filterByPk (7) -> findOneOrCreate ();

$ Mo-> setDescription ( "что-то");

if ($ mo-> validate ()) {$ mo-> save ()}

0 голосов
/ 09 ноября 2010

Самый быстрый способ обойти это - сначала запросить объект, а затем обновить его (чтобы вы не работали с отсоединенным объектом):

$mo = CategoryPeer::retrieveByPK(7);
$mo->setDescription('New description!');
$mo->save(); // should work since the entity was retrieved first

Если вам нужно иметь возможность обновляться без предварительного запроса, боюсь, я слишком новичок в Propel, чтобы советовать по этому поводу. Возможно, возможно сделать инструкцию SQL вручную, но также может быть способ присоединить экземпляр, для которого вы вручную установили идентификатор. Возможно, другой ответчик сможет просветить нас.

...