问题描述:
1. 多对多关联关系,a, b 表多对多, a_b 表是中间表。它们的模型分别是 AModel 和 BModel
2. A = AModel::create($data); // 成功创建 A 模型对象
3. A->b()->save($bData); // 这里报错:缺少关联表数据
通过跟代码,发现报错点是:BelongsToMany.php 文件中 attach 方法的 $id = $model->getLastInsID(); 表达式结果为0,即 getLastInsID() 返回0 导致下面执行 throw new Exception('miss relation data');
再分析代码,发现原因是 attach 方法的 $model->save($data); 方法使用了事务,即
/library/think/Model.php 文件中的 insertData 方法的代码中:
$db->startTrans();
try {
$result = $db->strict(false)
->field($allowFields)
->insert($this->data, $this->replace, false, $sequence);
// 获取自动增长主键
if ($result && $insertId = $db->getLastInsID($sequence)) {
$pk = $this->getPk();
foreach ((array) $pk as $key) {
if (!isset($this->data[$key]) || '' == $this->data[$key]) {
$this->data[$key] = $insertId;
}
}
}
// 关联写入
if (!empty($this->relationWrite)) {
$this->autoRelationInsert();
}
$db->commit();使用了事务,而在事务之外调用 pdo 的 lastInsertId 方法返回0。需要在 commit 之前调用才能得到插入的ID。Remember, if you use a transaction you should use lastInsertId BEFORE you commit
otherwise it will return 0
所以建议修改代码:
$model = new $this->model;
$model->save($data);
$id = $model->getLastInsID();
其中 $model 对象中已经保存自增主键的 id,那么 $id 从对象中获得就可以,不要使用 getLastInsID()
///////////////// 以下为旧内容////////////////////////////////
描述:a表,b表多对多关联,a_b 是中间表。当使用 $aModel->b()->attach($data) 向 b 和 a_b 表写数据时,报错:缺少关联表数据。
经过跟代码,发现 BelongsToMany.php 文件中的方法 attach 有问题。
代码如下:
public function attach($data, $pivot = [])
{
if (is_array($data)) {
if (key($data) === 0) {
$id = $data;
} else {
// 保存关联表数据
$model = new $this->model;
$model->save($data);
$id = $model->getLastInsID();
}
} elseif (is_numeric($data) || is_string($data)) {
// 根据关联表主键直接写入中间表
$id = $data;
} elseif ($data instanceof Model) {
// 根据关联表主键直接写入中间表
$relationFk = $data->getPk();
$id = $data->$relationFk;
}
if ($id) {
// 保存中间表数据
$pk = $this->parent->getPk();
$pivot[$this->localKey] = $this->parent->$pk;
$ids = (array) $id;
foreach ($ids as $id) {
$pivot[$this->foreignKey] = $id;
$this->pivot->insert($pivot, true);
$result[] = $this->newPivot($pivot, true);
}
if (count($result) == 1) {
// 返回中间表模型对象
$result = $result[0];
}
return $result;
} else {
throw new Exception('miss relation data');
}
}其中问题出在:当 $data 是一个数组,即向关联表写数据。代码会执行下面中的 else 部份if (is_array($data)) {
if (key($data) === 0) {
$id = $data;
} else {
// 保存关联表数据
$model = new $this->model;
$model->save($data);
$id = $model->getLastInsID();
}$model = new $this->model;$model->save($data);
上面两段代码完成向关联表写数据,事实上测试用的关联表中被写了数据。
但接下来: $id = $model->getLastInsID(); 返回值为 0 !问题所在!!!
意思是得不到关联表刚插入数据的 id 字段的值。
它导致接下去执行了代码:
if ($id){}
else {throw new Exception('miss relation data');}
也就是我遇到的 缺少关联表数据 的问题!
最佳答案