Doctrine 1.2 保存记录关系 UPDATE 而不是 INSERT
Posted
技术标签:
【中文标题】Doctrine 1.2 保存记录关系 UPDATE 而不是 INSERT【英文标题】:Doctrine 1.2 save Record relations UPDATE rather than INSERT 【发布时间】:2011-07-13 19:19:09 【问题描述】:我正在尝试级联保存一些用户:
$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_Connection_mysql_Exception: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
这不是 Doctrine 应该提供的开箱即用的东西吗?我在这里错过了什么吗?为什么我需要手动实现此行为?
补充说明
我们有 3 种情况决定记录是应该插入、更新还是简单关联:
1
我们数据库的全新用户 - 应该插入 我们数据库的全新位置 - 应插入2
我们数据库的全新用户 - 应该插入 现有位置 - 应链接到用户记录3
我们数据库的全新用户 - 应该插入 现有位置 ID,更新数据 - 应更新并链接到用户记录我们需要找到最有效的方法来做到这一点。显然我们可以在 preSave() 等中进行大量选择,我们只需要充分利用 Doctrine
【问题讨论】:
您确定位置表中“id”上的主键存在并且在模型类中正确写入了吗?你能提供模型类的代码吗?需要带有表格和关系描述的部分。 $this->hasColumn('location_id', 'integer', 8, array('type' => 'integer', 'length' => 8, 'fixed' => false, '无符号' => false, 'primary' => true, 'autoincrement' => false, )); 您在代码中引用字段“id”,而不是字段“location_id” - 为什么它应该工作? 【参考方案1】:通常我会这样做:
$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 钩子用于此类事情,我认为它们应该用于其他用例。
【讨论】:
这是我们前进的方向。一旦我们到达那里,我会给出完整的答案。这个答案当然有帮助。谢谢。【参考方案2】:也许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;
再见!
【讨论】:
以上是关于Doctrine 1.2 保存记录关系 UPDATE 而不是 INSERT的主要内容,如果未能解决你的问题,请参考以下文章
Doctrine 1.2 hasOne 覆盖 hasMany 关系