ThinkPHP一对一关联模型数据新增方法整理

发布时间:2022-12-10浏览次数:959 次
ThinkPHP中一对一模型关联的数据新增部分,其实官方文档中有介绍的,但是经常有人反馈说文档描述的比较混乱,所以对这块知识做以梳理,使其消除模糊,更加清晰。

关于ThinkPHP中一对一模型关联的数据新增部分,其实官方文档中有介绍的,但是经常有人反馈说文档描述的比较混乱,所以对这块知识做以梳理,使其消除模糊,更加清晰。

首先,之前我们也提到过,模型关联中的关联新增可以分为两大类,分步新增和同步新增。假设存在一个Article文章表,及Deatil文章详情表。在Article模型中定义detail()关联方法,为了后续统一,我们称Article表为主表,Detail表为关联表。表的字段基本如下:

Article:id,title

Detail:id,aid,content,其中aid为关联键

一、分步新增

即已存在文章标题等信息,但尚不存在文章内容。此时,我们需为Article中的数据,添加详情至Detail表中。方法如下:

$art = Article::find(4);
$data = ['content' => '345'];
$res = $art->detail()->save($data);

注意:1、这里的调用是 detail()方法,而不是detail属性,不存在关联数据时,detail属性也是不存在的,即Null。

2、detail()方法后,不支持使用data()方法,如下语句会引起报错(OneToOne关联模型下Save()方法缺少参数)。

$res = $art->detail($data)->save(); // 错误

分步新增的方法比较简单,即先取出主表数据,再使用关联方法新增关联数据即可。

二、同步新增

同步新增,即同时向主表和关联表中写入数据。官方称之为:关联自动写入。

同步新增细分的话又可分为:主动拆分数据(自己手动整理数据)和被动拆分数据两种。均需要使用到together()方法,区别是:主动拆分数据时,不需要指定子模型属性,被动拆分时,需指定。如下:

2.1 主动拆分数据

官方提供的示例代码为:

$article = new Article();
$article->title = '同步标题1';

$detail = new ArticleDetail();
$detail->content = '同步内容1';

$article->detail = $detail; // 将Detail模型对象赋给Article的detail属性

$res = $article->together(['detail'])->save();

表面上这段程序逻辑没问题,但实际会产生报错,save() must be of the type array。

事实上,手动整理数据比较低效,代码也较死板,因此这种方式我们一般不常用。

2.2 被动拆分数据

$article = new Article();
$data = [
	'title' => '同步标题1',
	'content' => '同步内容1'
];
$res = $article->data($data)->together(['detail'=>['content']])->save();

或:

$article = new Article();
$article->title = '同步标题2';
$article->content = '同步内容2';
$res = $article->together(['detail'=>['content']])->save();

以上两种方法是等效的,区别在于,方法一使用了data()方法向Article模型实例传递数据,方法二为直接赋值。

官方文档说明是:如果绑定了子模型的属性到当前模型,可以指定子模型的属性。实测,这里和是否绑定子模型属性到当前模型并无关系,只需使用together()方法进行指定即可。

需注意的是:data数据传递一定要在together()方法之前,比如下面的写法就会出现报错:

$res = $article->together(['detail'=>['content']])->save($data); // 错误
$res = $article->together(['detail'=>['content']])->data($data)->save(); // 错误

三、总结

1、仅在一对一关联同步写入时,需要使用together()方法;

2、together()方法的参数是必须数组形式,如:together(['detail']);

3、如果together()方法需指定关联属性的子属性,需使用数组形式,如:together(['detail'=>['content']])。

因为官方提供的同步写入主动拆分数据的示例无法正常运行,因此,在做数据关联插入时,我们基本只会用到together(['detail'=>['content']])这种形式。只有在数据更新和删除时,才会用到together(['detail'])这种形式

4、关联新增,同步写入数据时,数据传递(直接赋值或data()方法赋值)一定要在together()方法之前完成;

以上几点应该可以帮助大家理清ThinkPHP中数据关联新增了。

5、在一对多关联新增中,基本思路一致,区别是:在分步新增中,可以使用saveAll()批量添加。在同步新增时,

扫一扫,在手机上查看