今天着重讲述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化的方面编程的方式来实现,具体的实施方法还没有想好囧,哪位有这种尝试的可以给我留言哈。
分享到:
相关推荐
同时,我们也使用 `<if>` 标签来实现动态 SQL 语句的拼接。 <![CDATA[ ]]> 是 Mybatis 中一个非常有用的元素,它可以帮助我们解决特殊字符的转义问题,使得我们的代码更加简洁和易读。但是,我们也需要遵守 <!...
微信小程序支付JSAPI交易类型 已通过测试 返回例子如下: <xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <result_code><![CDATA[SUCCESS]]></result_code>
[CDATA[ 文本内容 ]]>`,其中"文本内容"部分不能包含字符串"]]>",以防止提前结束CDATA段。同时,CDATA段不能嵌套,也就是说,一个CDATA段内部不能再有另一个CDATA段。 要将Java对象转换成XML并包含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["&fromusername&"]]></ToUserName>" &_ "<FromUserName><![CDATA["&tousername&"]]></FromUserName>" &_ "<CreateTime>"&now&"</CreateTime>" &_ "<MsgType>news</MsgType>" &_ "<ArticleCount>3</...
[CDATA[留言内容]]></content> </message> </messages> </gbook> ``` 4. **DTD定义**: - 用于定义XML文档的结构和约束条件。 - 例如,`<gbook>` 元素包含了 `<info>` 和 `<messages>` 两个子元素。 ```xml...
</body> </note> ``` 在这个例子中,`<!DOCTYPE note [...]>`定义了文档类型为`note`,并且规定了`note`元素包含`to`、`from`、`heading`和`body`这四个子元素,每个子元素都允许包含字符数据(#PCDATA)。 外部...
**示例**:定义一个`<note>`元素,其包含`<to>`、`<from>`、`<heading>`和`<body>`四个子元素,其中`<to>`、`<from>`和`<heading>`元素仅包含文本数据,而`<body>`元素可以包含文本和子元素。 ```xml <!ELEMENT note...
2. '<':当遇到 '<' 时,状态变化到 '<',以判断是否是CDATA部分的起始。 3. '<!':继续往后读,检查是否是CDATA的开始。 4. '<![':继续,检查是否是CDATA的开始。 5. '<![C':继续,检查是否是CDATA的开始。 6. '...
ATTLIST course course_id ID #REQUIRED title CDATA #REQUIRED dept_name IDREF #REQUIRED credits CDATA #REQUIRED> <!ELEMENT instructor EMPTY> <!ATTLIST instructor IID ID #REQUIRED name CDATA #REQUIRED ...
[CDATA[10]]></LoginTimeOut> <QueryTimeOut><![CDATA[3600]]></QueryTimeOut> 原始set.xml数据库连接节点缺少以上两个节点请添加,LoginTimeOut为数据库连接超时时间,单位秒,QueryTimeOut为SQL语句执行超时时间...
[CDATA[FAIL]]></return> <return><![CDATA[商户号mch_id与appid不匹配]]></return> </xml> 原因是我拿到的商户号不是这个公众号的。一定要检查是不是这个公众号的商户号。 免责声明:本站所有文章和...
ENTITY % idType "ID CDATA #IMPLIED"> <!NOTATION ID NOTATION URI 'http://example.com/unique-id'> ]> <UserGroupSystem> <Group id="group1" ParentGroup="root"> <GroupName>管理员组</GroupName> ...
</body> </note> ``` 在上面的例子中,我们使用了外部的 DTD 文件“note.dtd”,其中包含了 DTD 声明: ```dtd <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!...
</body> </note> ``` 对应的`note.dtd`文件内容与内部声明相同。 使用DTD的好处主要包括: 1. **自包含性**:每个XML文件都可以携带其格式描述,方便理解和处理。 2. **标准化**:为不同的人提供了一种共同理解数据...