Propel ORM 的问题

发布于 2024-10-02 01:45:07 字数 517 浏览 2 评论 0原文

我在开发中使用 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();

我知道这可行,但由于我的项目的具体问题,我不能这样做。这就是问题的原因。

再次感谢!

Im using Propel ORM in my development and I have this issue:

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

Well, it doesn't updates the values. It throws an exception and says that I cannot insert a duplicate key. Is there a way to go around this?

Hope someone can help,
David

[EDIT]

I know that I can do this:

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

I know that this works, but due to my project's specific problems I cannot do that. So that's the WHY of the question.

Thanks again!

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

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

发布评论

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

评论(4

吃颗糖壮壮胆 2024-10-09 01:45:08

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

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

如果您需要能够在不先查询的情况下进行更新,恐怕我我是一个 Propel 新手,无法就此提供建议。可能可以执行手动 SQL 语句,但也可能有一种方法来附加您手动设置 id 的实例。也许另一个回答者可以启发我们。

The quickest way to work around this will be to query the entity first, and then update it (so that you're not working with a detached entity):

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

If you need to be able to update without querying first, I'm afraid I'm too much of a Propel novice to advise on that. It's probably possible to do a manual SQL statement, but there may also be a way to attach an instance for which you've manually set the id. Perhaps another answerer can enlighten us.

梦里兽 2024-10-09 01:45:08

使用 Find One Or Create 这将查找或创建一个对象

$mo = CategoryQuery::create()
->按Pk过滤(7)
->findOneOrCreate();

$mo->setDescription("某事");

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

Use Find One Or Create this will find or create a object

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

$mo->setDescription("something");

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

因为看清所以看轻 2024-10-09 01:45:07

无论如何,这似乎就像旧线程,这是我想提到的更新答案

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

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

This seems to be like the old thread anyway here is the updated answer I would like to mentions

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

In the above code the propel will either create new row or update the existing row based on the condition. Hope this might help someone.

〃温暖了心ぐ 2024-10-09 01:45:07

“伪造”现有对象

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

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

更新字段而不创建对象

如果您只想更新某些字段,甚至可能更新多个对象(例如:对于今天之前具有 executionDate 的所有 Order 对象,请设置将 status 更改为 "archived"),您可以通过调用 BasePeer::doUpdate() 自己。第一个参数是您选择的 Criteria 对象:今天之前具有 executionDate 的所有 Order 对象。第二个参数也是一个 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);

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

"Faking" an existing object

Propel chooses between an insert and an update based on the result of calling isNew() on the object you want to save (see your BaseCategory::save() function: $isInsert = $this->isNew();). So you can trick it into thinking it is an existing object by changing this property yourself: $mo->setNew(false);. isNew() and setNew() are defined in the BaseObject class.

In general, it may not be a good idea to work with partially-hydrated objects (which is what you seem to be doing here: you create an object, but then don't fill in all the properties with their actual database values). Some behaviors or your own code might depend on two properties of the object, and then give incorrect results. A simplified example: if you have an auto-generated field nameAndDescription, which you set to the concatenation of the name and the description fields on save (by extending the Propel object, via the new preInsert() and preUpdate() hooks), this will not do what you expect if you update your object like you do it here. But that's the only caveat I know, and it's probably a situation you have under control.

Updating fields without creating an object

If you only want to update some fields, and maybe even on multiple objects (for example: for all Order objects with an executionDate before today, set the status to "archived"), you can do this by calling BasePeer::doUpdate() yourself. The first argument is your select Criteria object: all Order objects with an executionDate before today. The second argument is also a Criteria object, but this is used to store the new values: status to "archived". It should look like this (untested):

// 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);

This method will of course not execute any preUpdate() or postUpdate() hooks you defined in PHP code, as the generated objects are completely bypassed. So only use this when it is absolutely necessary (for performance reasons?), and you know there are no other "stale" objects around.

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