简体   繁体   English

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

[英]Doctrine 1.2 save Record relations UPDATE rather than INSERT

I am trying to save in cascade some users:我正在尝试级联保存一些用户:

 $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;

In this situation I wish Doctrine to be smart enough and update the location 1 since I am changing the content for the id 1, but what I have instead is another insert.在这种情况下,我希望 Doctrine 足够聪明并更新位置 1,因为我正在更改 id 1 的内容,但我所拥有的是另一个插入。 I tried to workaround using a preSave() method inside User:我尝试在 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 );
    }
}

but when doctrine tries to UPDATE it doesn't have identifier and produces this error:但是当 doctrine 尝试更新时,它没有标识符并产生此错误:

Doctrine_Connection_Mysql_Exception: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

Isn't this something that Docrtrine should provide out of the box?这不是 Doctrine 应该提供的开箱即用的东西吗? Am I missing something here?我在这里错过了什么吗? Why do I need to implement this behavior by hand?为什么我需要手动实现这种行为?


Further Notes进一步说明

We have 3 cases that dictate whether the record should be inserted, updated, or simply related:我们有 3 种情况决定记录是应该插入、更新还是简单关联:

1 1

  • Brand new user to our database - should be inserted我们数据库的全新用户 - 应该插入
  • Brand new location to our database - should be inserted我们数据库的全新位置 - 应该插入

2 2

  • Brand new user to our database - should be inserted我们数据库的全新用户 - 应该插入
  • Existing location - should be linked to user record现有位置 - 应链接到用户记录

3 3

  • Brand new user to our database - should be inserted我们数据库的全新用户 - 应该插入
  • Existing location id, updated data - should be updated and linked to user record现有位置 ID,更新数据 - 应更新并链接到用户记录

We need to find the most efficient way to do this.我们需要找到最有效的方法来做到这一点。 Obviously we can do a multitude of selects in preSave() etc, we just need to get the most out of Doctrine显然我们可以在 preSave() 等中进行大量选择,我们只需要充分利用 Doctrine

Normally I would do something like this:通常我会做这样的事情:

$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;

Generally speaking Doctrine has a lot of convenient methods to deal with relations, the correct one to use depends on your exact needs.一般来说 Doctrine 有很多方便的方法来处理关系,正确的使用方法取决于您的具体需求。 For example you should specify how your location object is built, how many user instances do you have in the same code, if you have a location id or location data and so on.例如,您应该指定您的位置 object 是如何构建的,在同一代码中您有多少用户实例,如果您有位置 ID 或位置数据等等。

For point 1,2 and 3 in rails I'd use find_or_create_by method, which is not available in Doctrine, but you can always write it by yourself.对于 rails 中的第 1,2 和 3 点,我将使用 find_or_create_by 方法,该方法在 Doctrine 中不可用,但您始终可以自己编写。 So if you have the LocationTable class you can do this:所以如果你有LocationTable class 你可以这样做:

// 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'));

Don't use preSave hooks for this kind of things, I think they should be used for other use cases.不要将 preSave 钩子用于此类事情,我认为它们应该用于其他用例。

Maybe this will help也许会有所帮助

 $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;

Bye!再见!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM