CodeIgniter Active Record 与常规查询

Posted

技术标签:

【中文标题】CodeIgniter Active Record 与常规查询【英文标题】:CodeIgniter Active Record vs. regular queries 【发布时间】:2013-01-09 11:57:36 【问题描述】:

目前我在常规查询中使用 CodeIgniter,即:

$sql = "
    SELECT *
    FROM my_table
    WHERE item_id > 1
";    
$q = $this->db->query($sql);

我已经开始研究 ActiveRecord,它看起来确实不错,并且无论使用哪个数据库驱动程序都具有构建查询的优势 - 但是,我通常每个项目都严格使用单一数据库类型,所以这是对我来说并不是什么好处。

我发现常规查询(正如我在示例中所做的那样)在我看来更具可读性且更易于维护,因此我目前正在考虑保留常规查询。

除了上面提到的原因,我应该选择哪一个?出于什么原因?

谢谢

【问题讨论】:

【参考方案1】:

对我来说,我更喜欢运行常规查询,CI 的活动记录会消耗大量内存。因为它会将所有结果加载到内存中。如果你明白我的意思。至于复杂性,最好使用常规查询,而不是坚持 CI 的活动记录语法。

【讨论】:

嗨 tormexsans。谢谢。我仍然倾向于正常查询。根据迄今为止的回复,我没有真正的理由切换。再次感谢。 不好意思,已经一年多了,但是我不明白为什么常规查询的结果没有加载到内存中......查询的结果保存在一个变量中,然后返回...如果是常规查询,我不明白为什么不加载,你能解释一下吗?【参考方案2】:

在大多数情况下,我倾向于更喜欢 ActiveRecord。我发现它更具可读性,并且它使构建动态查询变得更加容易,因为您不必费力地将原始 SQL 块显式连接在一起。这意味着我可以毫不费力地将各种条件添加到我的查询构建器中,并得出一些非常易于阅读的内容。

在某些情况下,ActiveRecord 的 CodeIgniter 实现非常不适合(这让我很想念 Doctrine),我为此使用直接 SQL,但这种情况并不经常发生。

【讨论】:

嗨 Frequot,我是 Codeigniter 框架中 Active Records 的新手。我想知道 Active 记录是否支持动态模型类,我的意思是类似 Doctrine 的结构?【参考方案3】:

对于那些您厌倦了编写 SELECT blah blah 的简单查询,您可以使用活动记录稍微改变您的样式,因为在编写常规查询时,您很可能会出现语法错误。活动记录就是为此目的而设计的,除非您是专家,否则您不需要编写通常出错的可能性很高的语法。活动记录也提供了逃生设施。您不熟悉活动记录,它们(简单时)也是可读的。看看这个例子

$array  =   array(
        'user.username',
        'user.email',
        'user.password',
        'other.blah',
        'other.blah'
);
$where  =   array(
        'active'    =>  1,
        'other'     =>  'blahblah'
);  

return $this->db
        ->select($array)
        ->from('user')
        ->join('other','other.user_id = user.id','left')
        ->where($where)
        ->get()
        ->result();    

【讨论】:

嗨,Raheel,谢谢。我在编写查询方面还不错,而且我还使用绑定参数来使它们更安全,并且因为使用普通查询它们对我来说更具可读性,所以我现在会坚持下去 :-)【参考方案4】:

差不多两年后,我发现了这个问题。我的一些同事已经回答了几个优点或缺点,我只是想根据我的个人经验补充一点意见:

正如一些人所说,我也混合了使用活动记录和纯直接 sql 用于非常复杂的查询,原因是当您需要一个接收大量操作系统参数并相应更改查询的方法时使用它非常简单.例如,我有一个方法可以接收一个名为“options”的参数数组:

if(!empty($options['login']))

    $this->db->where('tl.login', $options['login']);

if(!empty($options['ip']))

    $this->db->where('tl.ip', $options['ip']);

if(!empty($options['sucesso']))

    $this->db->where('tl.sucesso', $options['sucesso']);


if(isset($options['usuarios_existentes']) && $options['usuarios_existentes'])

    $this->db->join('usuario u', 'tl.login = u.login');

else

    $this->db->join('usuario u', 'tl.login = u.login', 'LEFT');


if(!empty($options['limit']))

    $this->db->limit($options['limit']);

else

    $this->db->limit(50);


return $this->db->select('tl.id_tentativa_login, tl.login, DATE_FORMAT(tl.data, "%d/%m/%Y %H:%i:%s") as data, tl.ip, tl.sucesso', FALSE)
                ->from('logs.tentativa_login tl')
                ->order_by('tl.data', 'DESC')
                ->get()->result();

当然这只是一个简单的例子,但是我已经构建了具有数百行和条件的方法,可以更改通用的“get”方法,并且活动记录使它非常好并且非常易读,因为您不需要编写代码在它的中间正确格式化查询。

你甚至可以有连接和其他可以有条件的东西,所以你可以使用通用的集中式方法,这样可以避免重写大部分代码和复制部分代码(对维护来说很糟糕),它不仅可读,但它使您的查询保持快速,因为只加载您需要的内容:

if(!empty($opcoes['com_maquina']))

    if(strtoupper($opcoes['com_maquina'])=='SIM')
    
        $this->db->join('maquina m', 'm.id_local = l.id_local');
    
    elseif(strtoupper($opcoes['com_maquina'])=='NAO')
    
        $this->db->join('maquina m', 'm.id_local = l.id_local', 'LEFT');
        $this->db->where('m.id_maquina IS NULL');
    

activerecord 的另一个优点是它在语句中接受纯 SQL,例如子查询和其他内容,因此您可以随意使用它。

我说的是优点,但是,很明显纯 SQL 总是会执行得更快,并且不会有调用函数的开销。但说实话,在大多数情况下,php解析器会做的很快,不会以一种表现力的方式影响最终结果,如果你必须做很多手动条件,你的代码可能和activerecord一样慢无论如何解析器。

请注意,有时 activerecord 查询不会按您期望的方式工作,因为它会尝试以编程的逻辑方式构建查询,因此在大多数情况下使用“OR”语句时要小心你必须隔离它(和):

$this->db->where('(m.ultimo_status < DATE_ADD(NOW(), INTERVAL -2 HOUR) OR m.ultimo_status IS NULL)');

如果不加 ( ),OR 语句会影响整个 where 子句。 因此,一旦您习惯了 activerecord,它就会大有帮助,并且仍然可以进行快速且可读的查询。

【讨论】:

【参考方案5】:

嗯,我的主要原因是它运行快速且安全。因为它会自动转义值等。但是当涉及到复杂的查询时,我建议使用普通的查询字符串。

(不讨论连接等。因为 codeigniter 支持它并且可读性很好)更像是枢轴查询,或按行号选择(如下所示)

$query = $this->db->query('SELECT * FROM
  (SELECT  @row := @row + 1 as row, t.*
   FROM `default_red_albums` t, (SELECT @row := 0) r) AS view
WHERE `row` IN(' . $in . ')');

return $query->result();

【讨论】:

谢谢,克里斯。我仍然不相信我想切换到活动记录。我看不到某些查询使用 ActiveRecord 和其他查询的正常查询字符串的逻辑。不一致对我来说是一个缺点。所以在我读到一些清楚地告诉我为什么 ActiveRecord 更好的东西之前,我会坚持我正在做的事情——普通的查询字符串。感谢您的评论。 好吧,我同时使用这两种方法,只是尝试让我的模型方法名称真正具有描述性。例如:getRandomAlbums()、getRandomAlbumsByArtistIds()、checkAlbumIdExists()。如果这还不够,我建议您进行查询,因为我不能保证您不会偶然发现一些奇怪的查询。【参考方案6】:

ActiveRecord 并不总是按照您想要的顺序生成查询,这可能会导致不可预知的结果。例如这个模型:

        $this->db->select('page, content');
        $this->db->from('table');
        $array = array('title' => $searchq, 'content' => $searchq);
        $this->db->or_like($array, 'both'); 
        $this->db->where('showsearch', 'Yes'); 
        return $this->db->count_all_results();

产生这个查询:

        SELECT COUNT(*) AS `numrows`
        FROM (`table`)
        WHERE `showsearch` =  'Yes'
        AND  `title`  LIKE '%term%'
        OR  `content`  LIKE '%term%'

但我希望在查询结束时检查showsearch,这就是我首先将其放在那里的原因。但是 ActiveRecord 将它移动到查询的中间,我得到的结果不准确。

【讨论】:

这很有趣。谢谢,@Kenzo。我自己也喜欢普通的查询,但我从来不知道这一点。 group_start()group_end() 看起来是这个条件逻辑问题的合理解决方案。【参考方案7】:

使用对象模型进行查询有很大的好处。虽然您可以执行字符串解析和连接以针对多个函数构建查询,但这非常耗时且极易出错。使用对象模型,您可以传递引用并继续构建查询或在执行前将其传递给预处理器。

一个人为的示例可能是自动将日期过滤器添加到具有 creation_date 字段的表的所有查询中。

CI 还允许您将原始 SQL 与对象模型很好地混合。基本上,您构建了一个自定义查询,该查询将结果返回给水合物对象。

【讨论】:

以上是关于CodeIgniter Active Record 与常规查询的主要内容,如果未能解决你的问题,请参考以下文章

Codeigniter Active Record 类插入

使用 CodeIgniter Active Record 语句

CodeIgniter Active Record 与常规查询

CodeIgniter Active Record 中的 SQL 注释?

动态 Active Record 查询中的 Codeigniter 括号

Where 子句 CodeIgniter 中的 Active Record 问题