Fab*_*Fab 2 php orm doctrine save doctrine-1.2
我试图在级联中保存一些用户:
$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;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我希望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 );
}
}
Run Code Online (Sandbox Code Playgroud)
但是当doctrine尝试UPDATE时它没有标识符并产生这个错误:
Doctrine_Connection_Mysql_Exception: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
Run Code Online (Sandbox Code Playgroud)
这不是Docrtrine开箱即用的东西吗?我在这里错过了什么吗?为什么我需要手动实现这种行为?
我们有3个案例决定是否应该插入,更新或简单地关联记录:
我们需要找到最有效的方法来做到这一点.显然我们可以在preSave()等中做多个选择,我们只需要充分利用Doctrine
通常我会做这样的事情:
$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;
Run Code Online (Sandbox Code Playgroud)
一般来说,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'));
Run Code Online (Sandbox Code Playgroud)
不要将preSave挂钩用于此类事情,我认为它们应该用于其他用例.