关于thinkphp关联模型的HAS_ONE
2014-05-30 14:30
726 查看
距离第一次学习thinkphp有一年多了,也算是认识它和使用它一年多了吧,但是发现我对thinkphp还是有些不熟悉的地方,特别是模型。
最近开发二手房项目,里面用到模型,然后数据库是沿用之前的,框架转为thinkphp,之前一直自己设计数据库,所以模型可以做的和官方一样,但是这次因为数据库不便于改动,所以用HAS_ONE的时候,发现问题了。
我用的是3.1.3版本,
官方手册给出的HAS_ONE模型支持的关联属性是这样的:
我现在需要关联两种表:
Community(小区表)和Region(地区表)
小区表里的字段region和地区表里的rid是关联的
小区表
地区表
按照官方文档,写出来的模型是这样的
很明显关联没成功,我又回去查看官方手册,官方是这么说道
foreign_key:关联的外键名称
外键的默认规则是当前数据对象名称_id,例如:
UserModel对应的可能是表think_user (注意:think只是一个表前缀,可以随意配置)
那么think_user表的外键默认为 user_id,如果不是,就必须在定义关联的时候显式定义 foreign_key 。
我foreign_key没定义错,是rid,但是我需要关联的是小区表里的region=地区表里的rid呀,
怎么办,这个时候开源的优势就出来了,直接查看tp的源代码,
打开thinkphp/Extend/Model/RelationModel.php
找到第130行getRelation方法
今天是研究HAS_ONE 关键是看HAS_ONE
第149-156行代码
关键是151行
就是这里啦,然后再往上找$mappingFk和$pk变量
第135行-145行代码中有
151行$mappingFk
144行
下面是查找$pk经过
151行$pk
150行$pk = $result[$mappingKey];
139行 $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名
重点139行,mapping_key是否不是为空,不是空则 $val['mapping_key'],是空就$this->getPk()
$this->getPk();是获取主键的方法,我们定义模型的时候,官方文档没告诉我们定义mapping_key,所以tp默认找主键,所以我们关联的时候,如果两个表不是主键关联,那么将无法关联
下面是解决方案
还有,一般我是HAS_MANY的时候才用tp的关联模型,因为HAS_ONE还不如直接left join效率高,下回再分析,如有不对,希望大家指正。
最近开发二手房项目,里面用到模型,然后数据库是沿用之前的,框架转为thinkphp,之前一直自己设计数据库,所以模型可以做的和官方一样,但是这次因为数据库不便于改动,所以用HAS_ONE的时候,发现问题了。
我用的是3.1.3版本,
官方手册给出的HAS_ONE模型支持的关联属性是这样的:
mapping_type | 关联类型,这个在HAS_ONE 关联里面必须使用HAS_ONE 常量定义。 |
class_name | 要关联的模型类名 例如,class_name 定义为Profile的话则表示和另外的Profile模型类关联,这个Profile模型类是无需定义的,系统会自动定位到相关的数据表进行关联。 |
mapping_name | 关联的映射名称,用于获取数据用 该名称不要和当前模型的字段有重复,否则会导致关联数据获取的冲突。如果mapping_name没有定义的话,会取class_name的定义作为mapping_name。如果class_name也没有定义,则以数组的索引作为mapping_name。 |
foreign_key | 关联的外键名称 外键的默认规则是当前数据对象名称_id,例如: UserModel对应的可能是表think_user (注意:think只是一个表前缀,可以随意配置) 那么think_user表的外键默认为 user_id,如果不是,就必须在定义关联的时候显式定义 foreign_key 。 |
condition | 关联条件 关联查询的时候会自动带上外键的值,如果有额外的查询条件,可以通过定义关联的condition属性。 |
mapping_fields | 关联要查询的字段 默认情况下,关联查询的关联数据是关联表的全部字段,如果只是需要查询个别字段,可以定义关联的mapping_fields属性。 |
as_fields | 直接把关联的字段值映射成数据对象中的某个字段 这个特性是ONE_TO_ONE 关联特有的,可以直接把关联数据映射到数据对象中,而不是作为一个关联数据。当关联数据的字段名和当前数据对象的字段名称有冲突时,还可以使用映射定义。 |
Community(小区表)和Region(地区表)
小区表里的字段region和地区表里的rid是关联的
小区表
地区表
按照官方文档,写出来的模型是这样的
<?php class CommunityModel extends RelationModel { protected $_link = array( 'region'=>array( 'mapping_type'=>HAS_ONE, 'class_name'=>'region', 'mapping_name'=>'region', 'foreign_key' =>'rid', ), ); }然后action那边是
$id = $_GET['cid']; $Community = D('Community'); $where['cid'] = $id; $list = $Community->relation('region')->where($where)->select();打印出来的结果是
array(1) { [0] => array(27) { ["cid"] => string(18) "201201121788888888" ["username"] => string(14) "abc" ["name"] => string(18) "城市花园" ["region"] => NULL
很明显关联没成功,我又回去查看官方手册,官方是这么说道
foreign_key:关联的外键名称
外键的默认规则是当前数据对象名称_id,例如:
UserModel对应的可能是表think_user (注意:think只是一个表前缀,可以随意配置)
那么think_user表的外键默认为 user_id,如果不是,就必须在定义关联的时候显式定义 foreign_key 。
我foreign_key没定义错,是rid,但是我需要关联的是小区表里的region=地区表里的rid呀,
怎么办,这个时候开源的优势就出来了,直接查看tp的源代码,
打开thinkphp/Extend/Model/RelationModel.php
找到第130行getRelation方法
今天是研究HAS_ONE 关键是看HAS_ONE
第149-156行代码
case HAS_ONE: $pk = $result[$mappingKey]; $mappingCondition .= " AND {$mappingFk}='{$pk}'"; $relationData = $model->where($mappingCondition)->field($mappingFields)->find(); if (!empty($val['relation_deep'])){ $model->getRelation($relationData,$val['relation_deep']); } break;
关键是151行
$mappingCondition .= " AND {$mappingFk}='{$pk}'";这里就是关联的条件了,平时我们left join table on A=B
就是这里啦,然后再往上找$mappingFk和$pk变量
第135行-145行代码中有
$mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型 $mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名 $mappingFields = !empty($val['mapping_fields'])?$val['mapping_fields']:'*'; // 映射字段 $mappingCondition = !empty($val['condition'])?$val['condition']:'1=1'; // 关联条件 $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名 if(strtoupper($mappingClass)==strtoupper($this->name)) { // 自引用关联 获取父键名 $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; }else{ $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键 }下面是查找$mappingFk经过
151行$mappingFk
144行
$mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键
下面是查找$pk经过
151行$pk
150行$pk = $result[$mappingKey];
139行 $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名
重点139行,mapping_key是否不是为空,不是空则 $val['mapping_key'],是空就$this->getPk()
$this->getPk();是获取主键的方法,我们定义模型的时候,官方文档没告诉我们定义mapping_key,所以tp默认找主键,所以我们关联的时候,如果两个表不是主键关联,那么将无法关联
下面是解决方案
<?php class CommunityModel extends RelationModel { protected $_link = array( 'region'=>array(//关联的表名 'mapping_type'=>HAS_ONE, //关联类型 'class_name'=>'region', //需要关联的模型类名 'mapping_key' =>'region', //Community中关联的字段名 'mapping_name'=>'region', //关联的映射名称,用于获取数据用 'foreign_key' =>'rid', //region中关联的字段名 ), ); }其实就是加了
'mapping_key' =>'region', //Community中关联的字段名这样就可以了,tp手册中没告诉我们,可能是因为怕我们使用的时候没加索引,影响效率吧,
还有,一般我是HAS_MANY的时候才用tp的关联模型,因为HAS_ONE还不如直接left join效率高,下回再分析,如有不对,希望大家指正。
相关文章推荐
- 关于thinkphp模型中hasOne中字段同名的问题
- 关于thinkphp的几个问题:css路径问题,关联模型,
- 一对一关联模型,HAS_ONE
- 关于thinkphp关联模型的效率问题
- 【ThinkPHP】关于ThinkPHP关联模型和视图模型的一些心得 推荐
- Thinkphp中表关联HAS_ONE和BELONGS_TO的区别
- 关于thinkphp中关联模型的简单使用
- thinkphp 多对多关联模型(转)
- thinkphp 视图模型 关联模型
- 关于设备模型、设备与驱动关联的过程分析 - linux设备/驱动
- ThinkPHP中的关联模型注意点
- thinkphp 视图和关联模型
- ThinkPHP第十一天(关联模型使用,独立分组配置,MySQL concat用法)
- 关于hibernate中双向外键关联one-to-one的property-ref=的问题
- thinkphp关联模型具体使用
- PHP学习笔记——ThinkPHP开发指南-关联模型之关联定义
- ThinkPHP第十五天(setField、setInc、setDec、关联模型)
- ThinkPHP关联模型操作实例分析
- ThinkPHP第十四天(显示TRACE界面配置,关联模型详解定义)
- 关于Android开发导入已有项目遇到Project has no default.properties file! Edit the project properties to set one.问题的解决方法