Propel ORM问题

时间:2010-11-09 20:52:00

标签: php orm propel

我在开发中使用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 个答案:

答案 0 :(得分:3)

这似乎就像旧线程一样,这里是我想提及的更新答案

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

在上面的代码中,propel将创建新行或根据条件更新现有行。希望这可能有助于某人。

答案 1 :(得分:1)

“伪造”现有对象

Propel根据您要保存的对象调用isNew()的结果,在插入和更新之间进行选择(请参阅BaseCategory::save()函数:$isInsert = $this->isNew();)。因此,您可以通过自己更改此属性来欺骗它,使其认为它是现有对象:$mo->setNew(false);isNew()setNew()the BaseObject class中定义。

一般来说,使用部分水合物体可能不是一个好主意(这就是你在这里做的事情:你创建一个对象,但是不要用它们的实际数据库填充所有属性值)。某些行为或您自己的代码可能依赖于对象的两个属性,然后给出不正确的结果。一个简单的示例:如果您有一个自动生成的字段nameAndDescription,您在保存时将其设置为namedescription字段的串联(通过扩展Propel对象,通过新的preInsert()preUpdate()挂钩),如果您像在此处一样更新对象,这将无法达到预期效果。但这是我所知道的唯一警告,而且这可能是你掌控的情况。

在不创建对象的情况下更新字段

如果您只想更新某些字段,甚至可能更新多个对象(例如:对于今天之前Order的所有executionDate个对象,请将status设置为{{ 1}}),您可以通过自己调用BasePeer::doUpdate()来完成此操作。第一个参数是您的选择Criteria对象:今天之前具有"archived"的所有Order个对象。第二个参数也是Criteria对象,但这用于存储新值:executionDatestatus。它应该看起来像这样(未经测试):

"archived"

此方法当然不会执行您在PHP代码中定义的任何// 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()挂钩,因为生成的对象已被完全绕过。因此,只有在绝对必要时(出于性能原因?)才使用它,并且您知道周围没有其他“陈旧”对象。

答案 2 :(得分:0)

解决此问题的最快方法是首先查询实体,然后更新它(这样您就不会使用分离的实体):

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

如果你需要能够在不首先查询的情况下进行更新,我恐怕我太过于担心Propel新手了。可能有可能做一个手动SQL语句,但也可能有一种方法来附加您手动设置id的实例。也许另一位回答者可以启发我们。

答案 3 :(得分:0)

使用Find One或创建这将找到或创建一个对象

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

$钼> setDescription("东西&#34);

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