今天着重讲述SELECT上的实现。
在数据库操作中有两类SELECT,单表和多表,对于ORM对象来说多表总是非常复杂的,总结起来,表与表的关系有那么几种:
1对多
多对1
多对多
1对1
而将它们整合之后只有两种:
1对多
1对1
其中多对多变成了双向一对多(但在我的实现中使用了另外一种思路,后面会讲到,这种思路极大的简化了表的关系)而多对一本身来说就是1对多,只是主控方向不同而已,而且多对1实际上存在很少基本是在多对多中出现,因此基本可以忽略。
好了,下面来说说我对这两种模式的处理,实际上我采用了一种更简单的思维去考虑:
无论如何查询最终将返回一个hashmap(这应该是php的最佳形式,java中一个朋友曾经和我争论过这个,他认为Bean+list好过Hashmap+list,我个人的连接池均采用了hashmap+list,因为我想从根本上去摒弃java在类型上的不灵活,这是另外一个话题不到讨论),好了回到现在话题,那么经过我的乱七八糟的实验之后我只得出了两种结果,无论是哪种表关系,只有同时加载和延后加载两种风格。一种是单一数组比如
array(
"0"=>array(1,a,b),
"1"=>array(2,b,c)
)
另外一种模式是:
array(
"0"=>array(1,a,'extend'=>array(c,1,b))
)
实际上在实际的查询中前者我认为是LEFT JOIN语句,后者是一种我自己叫做后加载模式也就是select × from a select × from b where id in a。
而实际上我一开始去过于分析表和表的关系的时候其实是非常死胡同的,导致逻辑代码非常复杂,但却最后不知道怎么去写sql,而现在彻底摒弃了表和表的关系代以语句的实现来判断如何实现,这在很大程度上彻底简化了代码。当然我这种代码在本质上有很多致命弱点——查询语句会偏多带来的直接问题就是效率偏低,这个问题要在以后不断摸索和对数据库的熟悉之后再解决。
下面来看看部分实现代码:
module的构造,他需要塞入的参数1 连接池对象 表名 field列表,这个是可选的
function Module($dbObj,$dbName,$fieldList=array()){
$this->connectObj=$dbObj;
$this->dbname=$dbName;
$this->fieldList=$fieldList;
}
查询的类:其中核心的部分就是getsqlstr和后面的processonemore,processonemore就是我说的延迟加载查询的函数
function query($where="",$group="",$limit="",$order="",$foriegn="",$lazy=1,$fields='*'){
$sql=$this->getSqlStr($fields,$where,$group,$limit,$order,$foriegn);
$this->connectObj->sql=$sql;
$result = $this->connectObj->doSqlArray();
if($lazy){
$this->processOneMore(&$result);
}
return $result;
}
单一表查询:
private function processOneToOne(){
$ret="";
foreach($this->foriegnDb as $v){
if($v['type']==1){
$dbName=$v['db'];
$fKey=$v['key'];
$ret.=" LEFT OUTER JOIN {$this->connectObj->tablePrefix}{$dbName} ON {$this->connectObj->tablePrefix}{$dbName}.{$fKey}={$this->connectObj->tablePrefix}{$this->dbname}.{$this->key}";
}
}
return $ret;
}
多表查询:
private function processOneMore(&$result){
foreach ($this->foriegnDb as $v){
//ont to more
if($v['type']==2){
$className=$v['class'];
$dbName=$v['db'];
$key=$v['key'];
require_once(MODULE_ROOT.'/module.'.$className.'.php');
if(class_exists($className)){
$mObj=new $className();
foreach ($result as $k=>$v){
$cKey=$v[$this->key];
$r = $mObj->query("{$this->connectObj->tablePrefix}{$dbName}.{$key} = '{$cKey}'");
$result[$k]['extTable']=$r;
}
}
}
}
}
好,现在这样就基本实现了orm最基本的复合查询,不过现在的orm版本在sql上还比较单一,需要更多的sql优化,对类的处理进行大面积的优化才能有工业级性能,有时间的时候继续研究,这次其实参考了比较多的cakephp的思维方式,感觉还是不错的。
还有一个重要的问题:sql查询没有进行缓冲设计,这部分我打算是要用aop化的方面编程的方式来实现,具体的实施方法还没有想好囧,哪位有这种尝试的可以给我留言哈。
分享到:
相关推荐
XML 元素中,"<" 和 "&" 是非法的。"<" 会产生错误,因为解析器会把该字符解释为新元素的开始。"&" 也会产生错误,因为解析器会把该...[CDATA[文本内容]]>CDATA的文本内容中不能出现字符串“]]>”,另外,CDATA不能嵌套。
[CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></...
[CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml...
ATTLIST 电话 类别 CDATA "移动电话"> ]> <联系人列表> <说明>&content;</说明> <联系人> <姓名>刘保文</姓名> <ID>201003101115</ID> <公司>腾飞汇通有限公司</公司> <电话 类别="移动电话">18993380967</...
自己将数据导入到xml中的,希望有需要的朋友可以自己下载,格式为<!DOCTYPE PCAroot[ <!ELEMENT PCAroot (Province*)> <!ELEMENT Province (City*)> <!ELEMENT City (Area*)> <!ELEMENT Area (#PCDATA)> <!...
<preconditions><![CDATA[1.使用udp_bi用户在PLSQL正常登陆UAT数据库<br> (UAT数据库IP: 10.0.13.178)<br> 2.数据库脚本已下载至本地环境]]></preconditions><importance><![CDATA[2]]></importance><steps> <step>
本文给大家解析使用<![CDATA[ ]]>解决xml文件不被转义的问题, 对mybatis 中的<![CDATA[ ]]>相关知识感兴趣的朋友一起看看吧
[CDATA["&fromusername&"]]></ToUserName>" &_ "<FromUserName><![CDATA["&tousername&"]]></FromUserName>" &_ "<CreateTime>"&now&"</CreateTime>" &_ "<MsgType>news</MsgType>" &_ "<ArticleCount>3</...
<srvver>1.0</srvver> <srvcode>000</srvcode> <payload> <param type=XML key=data> <![CDATA[ <Response> <Execution> <Status code=0 sql_code=0 description=执行成功!/> </Execution> <ResponseContent...
[CDATA[10]]></LoginTimeOut> <QueryTimeOut><![CDATA[3600]]></QueryTimeOut> 原始set.xml数据库连接节点缺少以上两个节点请添加,LoginTimeOut为数据库连接超时时间,单位秒,QueryTimeOut为SQL语句执行超时时间...
[CDATA[gh_33bb5907f91e]]></ToUserName> <FromUserName><![CDATA[ojLh3jkYtiszyEY-_sM_8yrNxSc4]]></FromUserName> <CreateTime>1363231643</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><...
微信小程序支付JSAPI交易类型 已通过测试 返回例子如下: <xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <result_code><![CDATA[SUCCESS]]></result_code>
[CDATA[//><!-- var scrollPic_02 = new ScrollPic(); scrollPic_02.scrollContId = "ISL_Cont_1"; //内容容器ID scrollPic_02.arrLeftId = "LeftArr";//左箭头ID scrollPic_02.arrRightId = "RightArr"; //...
[CDATA[http://t{$serverpart}.tianditu.cn/DataServer?T=cia_w&X={$x}&Y={$y}&L={$z}]]></url> <serverParts>0 1 2 3 5 6 7</serverParts> <backgroundColor>#00000000</backgroundColor> </customMapSource> </...
[CDATA[FAIL]]></return> <return><![CDATA[openid is invalid]]></return> </xml> 原因是,传有效过去不是的opendid。不小心看错了,把用户id 当做openid传过去了。 当统一下单成功,会返回以下格式的...
android 使用saxparser 解析<![CDATA[ ]]>标签数据。 见附件实例
4、支持 CDATA 。5、开源(如果有任何问题可以自己修改)。缺点:。1、加载速度稍微逊色于支持库,但是查询速度很快。2、不支持DTD,也就是类似于如下的节点。 <!DOCTYPE note [。 <!ELEMENT note (to,from,...
<name>s1</name><!--这个name和teacher根元素中的name发生命名冲突--> <sex>girl</sex><!--这个sex和teacher根元素中的sex发生命名冲突--> </student> </teacher> 2、名域的声明 (1)直接定义 xmlns:...
<>]*\shref\s*=\s*["']?reptile-replace-string["'\s][^<>]*>]]></value> </property> <property name="getRegexUrl"> <!-- 提取最终URL --> <ref bean="ahrefGetRegexUrl"/> </property> </bean>...