thinkphp框架中“关联操作”的完整定义详解

在复杂的关联操作中,如果要给关联定义增加可选的属性,我们可以采用完整定义方式

完整定义的格式是:

protected $_link = array(

‘关联1‘  =>  array(

‘该表的关联方式的属性1‘ => ‘定义‘,

‘该表的关联方式的属性N‘ => ‘定义‘,

),

‘关联表名2‘  =>  array(

‘该表的关联方式的属性1‘ => ‘定义‘,

‘该表的关联方式的属性N‘ => ‘定义‘,

),

...

);

在上面的格式描述中,对于属性我们使用了一个修饰词:该表的关联方式的属性。

关联操作的定义之所以觉得复杂和容易出错,也许是因为可定义的属性比较多,而且因为各种关联关系不同,可定义的属性也有部分区别,其实只要理解透这个知识点,你会发现关联操作其实也很简单。

我们换一种方式去啃下这个最麻烦的难点,先来了解所有允许定义的属性含义,然后再按照各种关联关系去对号入座。

完整方式的定义,替换上面的格式,会似这样,这里以Area表进行示例说明允许定义的属性这个概念

class UserModel extends Model{

protected $_link = array(

‘Area‘=>array(

‘mapping_type‘=> BELONGS_TO,

‘mapping_name‘=> ‘Area‘,

‘class_name‘ => ‘Area‘,

‘foreign_key‘ => ‘area_id‘,

),

);

}

上面代码中,mapping_type,foreign_key ...这些,就是允许定义的属性

-------------------------所有可定义的属性概述--------------------------------
mapping_type  

用以定义该表与主表的关联类型mapping_type所定义的内容必须是常量,共有下面四种方式:

HAS_ONE  表示当前模型(主表)拥有一个子对象,例如本例中的user_info,每个会员对应一个资料表

Belongs_to  表示当前模型从属于另外一个父对象,例如每个会员都从属于一个地区

HAS_MANY  表示当前模型拥有多个子对象,例如每个用户有多个兴趣消费卡

MANY_TO_MANY 表示当前模型可以属于多个对象,而父对象则可能包含有多个子对象,通常两者之间需要一个中间表类约束和关联。例如本例中的每个会员可以属于多个兴趣组,每个兴趣组可以有多个用户

class_name

要关联的模型类名称。

例如示例代码所定义的Area,再次提醒,一定要确保已定义了此模型类(AreaModel)。

mapping_name

关联的映射名称,用于获取数据用,作为数据集中与主表字段并列的数据索引

该名称不能与当前模型的字段重复,否则会导致关联数据获取的冲突mapping_name没有定义的话,会取class_name的定义作为mapping_name。即模型类名称

foreign_key

关联的外键名

foreign_key如果没定义,则默认是 当前数据对象名称+_id 作为外键

例如:UserModel对应的表是think_user(注意:think只是一个数据表前缀,可以随意配置)

那么think_user表的外键默认为user_id,如果不是,就用该属性进行显式指定,例如数据表定义的外键是userId,则使用‘foreign_key‘=>‘userId‘,这种方式去申明

Condition

关联条件,在关联查询的时候会自动带上外键的值,如果有额外的查询条件,可以使用该属性进行定义

mapping_fields

关联要查询的字段

如果没有定义,默认关联查询的关联数据是该关联表的全部字段。

如果仅仅是需要查询其中的个别字段,可以使用该属性进行指定

as_fields

直接把关联的字段值映射成数据对象中的某个字段

这个特性是ONE_TO_ONE(包括HAS_ONE 和 BELONGS_TO)关联关系特有的,可以直接把关联数据映射到数据对象中,而不是作为一个关联数据。例如当关联数据的字段名和当前数据对象的字段名称有冲突时,可以使用下面这种方式进行定义:

‘as_fields‘=>‘email,nickname:username‘,没有定义该属性时数据类似于:

["id"] => string(1) "2"

["name"] => string(8) "thinkphp"

["Card"] => array(1) {

[0] => array(1) {

["card"] => string(8) "88888888"

}

如果定义了映射,则类似于

["id"]   => string(1) "2"

["name"] => string(8) "thinkphp"

["card"] => string(8) "88888888"

parent_key

引用关联的关联字段

默认为parent_id (BELONGS_TO和HAS_MANY才有此属性)

自引用关联是一种比较特殊的关联,也就是关联表就是当前表。

mapping_limit

关联要返回的记录数目(HAS_MANY和MANY_TO_MANY才有此属性)

mapping_order

关联查询的排序 (HAS_MANY和MANY_TO_MANY才有此属性)

relation_foreign_key

关联表的外键名称 (MANY_TO_MANY独有属性)

默认的关联表的外键名称是 表名+_id

例如本示例中的relation_foreign_key是group_id

如果不符合,可通过此属性进行指定

relation_table

关联的中间表名称 (MANY_TO_MANY独有属性)

如果没有设置该属性,默认通过当前模型的getRelationTableName方法自动获取

例如当前模型是User,关联模型是Group,那么关联表的名称会默认使用user_group这样的格式。

默认的中间表命名规则是:

如果两个表存在一个对应的中间表,该中间表的命名方式为

数据表前缀+_ +关联操作的主表名+_+关联表名

例如本示例中,由think_user表操作关联表,所以和think_group表的中间表名称是think_user_group,如果是从think_group表来操作,那么中间命名是think_group_user,也就是说,多对多关联的设置,必须有一个Model类里面需要显式定义中间表,否则双向操作会出错。

另外,中间表的字段无需要有id主键,(不过就算建立了这个字段也不会影响中间表操作的)中间表通常只是由 user_id 和 group_id 构成就可以了。

如果中间表不符合上面的规则,则需要通过该属性去显式指定中间表名称。

各种关联关系类型可用属性归纳如下,使用中可对照此表和参考上面定义解释

HAS_ONE 可用属性

mapping_type

class_name

mapping_name

foreign_key

condition

mapping_fields

as_fields

BELONGS_TO 可用属性

mapping_name

foreign_key

mapping_fields

condition

parent_key

as_fields

HAS_MANY 可用属性

mapping_name

foreign_key

parent_key

mapping_fields

mapping_limit

mapping_order

MANY_TO_MANY 可用属性

mapping_name

foreign_key

elation_foreign_key

mapping_limit

mapping_order

relation_table

关联定义好后,我们就可以轻松使用关联操作了。

以下示例代码来自官方总工程师的关联操作示例,先贴出所有代码再对重点要注意的地方进行讲解

<?php

class IndexAction extends Action{

public function index(){

$User = D("User");

/*-------------- 关联写入 -------------------------------*/

// 添加用户数据

$User->name =  ‘thinkphp‘;

$User->area_id   =  1;//东区

// 用户档案数据

$User->UserInfo =  array(

‘email‘  =>‘[email protected]‘,

‘nickname‘ =>‘流年‘,

);

// 用户的消费卡数据

$User->Card   =  array(

array(‘id‘=>1,‘card‘=>‘12345678‘),// 消费卡帐号1

array(‘id‘=>2,‘card‘=>‘88888888‘),// 消费卡帐号2

);

// 用户的所属兴趣组数据

$User->Group =  array(

array(‘id‘=>1),// 琴

array(‘id‘=>2),// 棋

);

// 关联添加用户数据

$id = $User->relation(true)->add();

// 如果用户数据不是User模型 而是一个Data数组

// 可以使用

// $id = $User->relation(true)->add($Data);

$this->assign(‘info1‘, ‘用户数据关联写入完成!‘);

/*-------------- 关联查询 -------------------------------*/

$user   =  $User->relation(true)->find($id);

$this->assign(‘user1‘,$user);

$user   =  $User->relation(‘UserInfo‘)->find($id);

$this->assign(‘user2‘,$user);

$list   =  $User->relation(true)->findAll();

$this->assign(‘list‘,$list);

/*-------------- 关联更新 -------------------------------*/

$user[‘id‘]   = $id;

$user[‘name‘] = ‘tp‘;

// HAS_ONE 关联数据的更新直接赋值

$user[‘UserInfo‘][‘email‘] =  ‘[email protected]‘;

// 注意HAS_MANY 的关联数据要加上主键的值

// 可以更新部分数据

$user[‘Card‘] = array(

array(‘id‘=>1,‘card‘=>‘66666666‘), // 更新主键为1的记录

array(‘card‘=>‘77777777‘),// 增加一条新的记录

);

// MANY_TO_MANY 的数据更新是重新写入

$user[‘Group‘] =  array(

array(‘id‘=>2),

);

$User->where(‘id=‘.$id)->relation(true)->save($user);

// 查询更新后的数据

$user   =  $User->relation(true)->find($id);

$this->assign(‘user3‘,$user);

/*-------------- 关联删除 -------------------------------*/

$User->relation(true)->delete($id);

/*--------------------------------------------------------*/

$this->assign(‘info2‘, ‘用户ID为‘.$id.‘的数据已经关联删除!‘);

$this->assign(‘id‘,$id);

$this->display();

}

}

?>

代码注解:

TP关联操作支持手动关联和自动关联,我们看到上面代码使用的是手动关联,通过在连贯操作中的relation()方法进行控制,如果需要自动关联操作,可以在UserModel中设置相应属性。

class UserModel extends RelationModel{

protected $autoSaveRelations = true;        // 自动关联保存

protected $autoDelRelations  = true;        // 自动关联删除

protected $autoAddRelations  = true;        // 自动关联写入

protected $autoReadRelations = true;        // 自动关联查询

protected $_link = array(....);

}

例如当设置了自动关联查询属性为true时,使用$User->select(),系统会自动把所有定义的关联数据都查询出来,自动关联的应用可以自己进行测试体验,官方的建议是:当给模型定义了多个关联的时候,要尽量避免使用自动关联操作,以免影响性能

再来看上面的代码,插入数据时我们使用了这种方式:

// 用户档案数据

$User->UserInfo =  array(

‘email‘  =>‘[email protected]‘,

‘nickname‘ =>‘流年‘,

);

是因为我们以User模型为核心对其它模型类进行关联定义的,其它模型类的mapping_name属性所定义的值,会被映射到User数据对象中成为User数据对象的其中一个属性,黙认mapping_name属性是关联的模型类名称。

如果是ONE_TO_ONE关联关系,并且定义了as_fields字段映射,则as_fields所设置的字段,会直接作为user数据对象的字段,这种情况在数据处理方式上,和单表模型是相同的,即直接赋值就可以:

$User->email    = ‘[email protected]‘;

$User->nickname = ‘流年‘;

relation()方法在ThinkPHP1.6版中进行了改进,简化了以前的几种我们所熟悉的xFind(),xFindAll(),relationGet(),relationAdd(),relationSave(),relationDel()这些方法,全部整合到了新定义的relation()中,直接支持使用参数进行连贯操作。

当需要进行关联处理时,我们使用relation(ture)这种方式:

$id = $User->relation(true)->add();

如果要指定关联数据,可以如34行代码中那样,在relation方法中传入参数:

$user =$User->relation(‘UserInfo‘)->find($id);

至于关联更新的需要注意的是HAS_ONE 关联数据的更新直接赋值则可,

$user[‘UserInfo‘][‘email‘] =  ‘[email protected]‘;

如果是HAS_MANY 的关联数据则要加上主键的值,可以更新部分数据或添加新的数据

$user[‘Card‘] = array(

array(‘id‘=>1,‘card‘=>‘66666666‘), // 更新主键为1的记录

array(‘card‘=>‘77777777‘),// 增加一条新的记录

);

MANY_TO_MANY关联在插入和更新时,都会自动先将原来关联的数据删除再进行处理。

打开Runtime/Logs/的log日志或开启debug模式时,可以留意一下生成sql

文章如需转载请注明:转载自PHPthink 本文链接地址:http://www.phpthink.cn/html/221.html

时间: 2024-08-03 23:32:23

thinkphp框架中“关联操作”的完整定义详解的相关文章

VC中预处理指令与宏定义详解

刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个经典的例子 使用预处理与宏定义最经典的例子莫过于加在一个头文件中以避免头文件被两次编译.试想这种的情况,有一个文件headerfile.h 它被包含在headerfile1.h中,同时在headerfile2.h 中也被包含了,现在有一个CPP文件,implement.cpp 包含了headerfi

HTML中 DOM操作的Document 对象详解(收藏)

Document 对象Document 对象代表整个HTML 文档,可用来访问页面中的所有元素.Document 对象是 Window 对象的一个部分,可通过 window.document 属性来访问. Document 对象的集合:(1)all[]:all 集合返回对文档中所有 HTML 元素的引用.语法: document.all[i]document.all[name]document.all.tags[tagname] 说明:第一:all[] 是一个多功能的类似数组的对象,它提供了对文

Spring 4.2框架中注释驱动的事件监听器详解

事件交互已经成为很多应用程序不可或缺的一部分,spring框架提供了一个完整的基础设施来处理瞬时事件.下面我们来看看Spring 4.2框架中基于注释驱动的事件监听器. 1.早期的方式 在早期,组件要从Spring事件获知自定义域事件中获取通知,那么组件必须实现ApplicationListener接口并覆写onApplicationEvent方法. @Component class OldWayBlogModifiedEventListener implements ApplicationLi

Spring 框架中注释驱动的事件监听器详解

事件交互已经成为很多应用程序不可或缺的一部分,Spring框架提供了一个完整的基础设施来处理瞬时事件.下面我们来看看Spring 4.2框架中基于注释驱动的事件监听器. 1.早期的方式 在早期,组件要从Spring事件获知自定义域事件中获取通知,那么组件必须实现ApplicationListener接口并覆写onApplicationEvent方法. @Component class OldWayBlogModifiedEventListener implements ApplicationLi

ssh框架中struts.xml 的配置参数详解

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <!-- <?xml ?>中的为

制作类似ThinkPHP框架中的PATHINFO模式功能(二)

距离上一次发布的<制作类似ThinkPHP框架中的PATHINFO模式功能>(文章地址:http://www.cnblogs.com/phpstudy2015-6/p/6242700.html)已经过去好多天了,今晚就将剩下的一些东西扫尾吧. 上一篇文章已经实现了PATHINFO模式的URL,即我们访问MVC模式搭建的站点时,只需要在域名后面加上(/module/controller/action)即可,很智能化.并且通过new Object时的自动触发函数实现类文件的自动载入,因此只要我们搭

ThinkPHP框架模型连贯操作(八)

原文:ThinkPHP框架模型连贯操作(八) Thinkphp的连贯操作使用起来也是很灵活: *可能这里有的mysql函数没全部罗列出来,大家可以举一反三,形式雷同 一.常用连贯操作 1.where 帮助我们设置查询条件 2.order 对结果进行排序 $arr=$m->order('id desc')->select(); $arr=$m->order(array('id'=>'desc','sex'=>'asc'))->select(); 多个字段排序 //数组形式

浅析Thinkphp框架中运用phprpc扩展模式

浅析Thinkphp框架中应用phprpc扩展模式 这次的项目舍弃了原来使用Axis2做web服务端的 方案,改用phprpc实现,其一是服务端的thinkphp已集成有该模式接口,其二是phprpc传输的数据流相对于普通WebService中的 XML或JSON形式的数据量明显减少,而且因为数据量的关系解析速度明显比较快~~ 说实话,以前还真不知道有phprpc这个协议的,本打算使用 sina的api的restlet形式开发,但自己写库的话会花比较多的时间,而现在轻量级的php框架支持rest

thinkphp 框架中的一部分方法解析

 1 thinkphp 框架 中判断输入的数值和数据库中的数值是否一致    首先 需要在view文件夹下建一个模板 名为zhuce.html <html> <head> <script src="__ROOT__/Public/js/jquery-1.11.2.min.js"></script> </head> <body> <div> 账号:<input type="text&quo