Doctrine 1.2保存记录关系UPDATE而不是INSERT

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个案例决定是否应该插入,更新或简单地关联记录:

1

  • 应该插入我们数据库的全新用户
  • 应该插入我们数据库的全新位置

2

  • 应该插入我们数据库的全新用户
  • 现有位置 - 应链接到用户记录

3

  • 应该插入我们数据库的全新用户
  • 现有的位置ID,更新的数据 - 应该更新并链接到用户记录

我们需要找到最有效的方法来做到这一点.显然我们可以在preSave()等中做多个选择,我们只需要充分利用Doctrine

Fab*_*bio 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;
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挂钩用于此类事情,我认为它们应该用于其他用例.