我试图以级联方式保存一些用户:
$user = new User();
$user->name = 'xxx';
$user->location->id = 1;
$user->location->name = 'yyy';
$user->save;
$user2 = new User();
$user2->name = 'zzz';
$user2->location->id = 1;
$user2->location->name = 'yyy';
$user2->location->zip = '123456';
$user2->save;
在这种情况下,我希望Doctrine足够智能并更新位置1,因为我正在更改id 1的内容,但我所拥有的是另一个插入。 我试图在User:
中使用preSave()方法解决方法public function preSave( Doctrine_Event $event )
{
$invoker = $event->getInvoker();
if ( /...decide to UPDATE the record .../ )
{
$invoker->state( Doctrine_Record::STATE_DIRTY );
}
else
{
$invoker->state( Doctrine_Record::STATE_CLEAN );
}
}
但是当doctrine尝试UPDATE时它没有标识符并产生这个错误:
Doctrine_Connection_Mysql_Exception: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
这不是Docrtrine开箱即用的东西吗?我在这里错过了什么吗?为什么我需要手动实现这种行为?
我们有3个案例要求记录是应该插入,更新还是仅仅相关:
我们需要找到最有效的方法来实现这一目标。显然我们可以在preSave()等中做多个选择,我们只需要充分利用Doctrine
答案 0 :(得分:6)
通常我会做这样的事情:
$location = new Location();
$location->name = 'yyy';
$location->save(); // this will assign location id using autoincrement
// or alternatively if you have generated table classes
// $location = LocationTable::getInstance()->create(array('name' => 'yyy');
// or if you have an already existing location
// $location = LocationTable::getInstance()->find($location_id);
// keep in mind that if you haven't generated any table class you should replace
// LocationTable::getInstance() with Doctrine_Core::getTable('Location');
$user = new User();
$user->name = 'xxx';
$user->location = $location;
// or $user->Location = $location; // the case of the l depends on how you have declared the model relationships
$user->save;
$user2 = new User();
$user2->name = 'zzz';
$user2->location = $location;
$user2->save;
一般来说,Doctrine有很多方便的方法来处理关系,正确使用它取决于你的确切需求。例如,您应该指定您的位置对象的构建方式,相同代码中有多少个用户实例,如果您有位置ID或位置数据等等。
对于rails中的第1,2和3点,我使用了find_or_create_by方法,该方法在Doctrine中不可用,但您可以自己编写它。因此,如果你有LocationTable
课程,你可以这样做:
// in LocationTable class
public function findOrCreateBy($fieldName, $value, array $data = array())
{
if (!$record = $this->findBy($fieldName, $value)) {
// record doesn't exist, create it with provided data
$record = $this->create(array($fieldName => $value));
}
// update record data
$record->fromArray($data);
// optionally save the record, depend on your needs
$record->save(); // it won't trigger actual save if record fields aren't updated
return $record;
}
// then in your example code you could fetch the location code with
$location = LocationTable::getInstance()
->findOrCreateBy('name', 'yyyy', array('field_to_update' => 'new value'));
不要将preSave挂钩用于此类事情,我认为它们应该用于其他用例。
答案 1 :(得分:0)
也许this会有所帮助
$user = new User();
$user->name = 'xxx';
$user->location->id = 1;
$user->location->name = 'yyy';
$user->save;
$user2 = new User();
$user2->name = 'zzz';
$user2->location->assignIdentifier(1);
$user2->location->name = 'yyy';
$user2->location->zip = '123456';
$user2->save;
再见!