Propel ORM 的问题
我在开发中使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
解决此问题的最快方法是首先查询实体,然后更新它(这样您就不会使用独立的实体):
如果您需要能够在不先查询的情况下进行更新,恐怕我我是一个 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):
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.
使用 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() }
无论如何,这似乎就像旧线程,这是我想提到的更新答案
在上面的代码中,propel 将根据条件创建新行或更新现有行。希望这可以帮助某人。
This seems to be like the old thread anyway here is the updated answer I would like to mentions
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.
“伪造”现有对象
Propel 根据对要保存的对象调用
isNew()
的结果在插入和更新之间进行选择(请参阅您的BaseCategory::save()< /code> 函数:
$isInsert = $this->isNew();
)。因此,您可以通过自己更改此属性来欺骗它认为它是一个现有对象:$mo->setNew(false);
。isNew()
和setNew()
在BaseObject
类。一般来说,使用部分水合的对象可能不是一个好主意(这就是您在这里所做的:创建一个对象,但不要用其实际的数据库值填充所有属性)。某些行为或您自己的代码可能取决于对象的两个属性,然后给出不正确的结果。一个简化的示例:如果您有一个自动生成的字段
nameAndDescription
,您在保存时将其设置为name
和description
字段的串联(通过新的preInsert()
和preUpdate()
钩子扩展 Propel 对象),如果您像这样做一样更新对象,则不会达到您所期望的效果这里。但这是我所知道的唯一警告,而且这可能是您可以控制的情况。更新字段而不创建对象
如果您只想更新某些字段,甚至可能更新多个对象(例如:对于今天之前具有
executionDate
的所有Order
对象,请设置将status
更改为"archived"
),您可以通过调用BasePeer::doUpdate()
自己。第一个参数是您选择的 Criteria 对象:今天之前具有executionDate
的所有Order
对象。第二个参数也是一个 Criteria 对象,但它用于存储新值:status
到“archived”
。它应该看起来像这样(未经测试):该方法当然不会执行您在 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 yourBaseCategory::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()
andsetNew()
are defined in theBaseObject
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 thename
and thedescription
fields on save (by extending the Propel object, via the newpreInsert()
andpreUpdate()
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 anexecutionDate
before today, set thestatus
to"archived"
), you can do this by callingBasePeer::doUpdate()
yourself. The first argument is your select Criteria object: allOrder
objects with anexecutionDate
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 method will of course not execute any
preUpdate()
orpostUpdate()
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.