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()
->find开发者_JS百科ByPk(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!
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.
"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.
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.
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() }
精彩评论