今天着重讲述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化的方面编程的方式来实现,具体的实施方法还没有想好囧,哪位有这种尝试的可以给我留言哈。


你可能感兴趣的:(设计模式,sql,PHP,orm,cakephp)