首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与面向对象的概念作斗争

与面向对象的概念作斗争
EN

Stack Overflow用户
提问于 2013-11-22 02:17:32
回答 2查看 1.3K关注 0票数 14

我真的很纠结于反复出现的OOP /数据库概念。

请允许我解释一下伪PHP代码的问题.

假设您有一个"user“类,它从构造函数中的users表加载数据:

代码语言:javascript
复制
class User {
    public $name;
    public $height;

    public function __construct($user_id) {
        $result = Query the database where the `users` table has `user_id` of $user_id
        $this->name= $result['name'];
        $this->height = $result['height'];
    }
}

简单太棒了。

现在,我们有了一个"group“类,它从与groups_users表连接的groups_users表中加载其数据,并从返回的user_id中创建user对象:

代码语言:javascript
复制
class Group {
    public $type;
    public $schedule;
    public $users;

    public function __construct($group_id) {
        $result = Query the `groups` table, joining the `groups_users` table,
                    where `group_id` = $group_id
        $this->type = $result['type'];
        $this->schedule = $result['schedule'];

        foreach ($result['user_ids'] as $user_id) {
            // Make the user objects
            $users[] = new User($user_id);
        }
    }
}

一个组可以有任意数量的用户。

美丽,优雅,惊人..。在纸上。然而,在现实中,制造一个新的组对象..。

代码语言:javascript
复制
$group = new Group(21);  // Get the 21st group, which happens to have 4 users

...performs 5查询,而不是1. (组1,每个用户1)。更糟糕的是,如果我创建了一个community类,其中包含许多组,其中每个组中都有许多用户,那么就会运行大量的查询!

这个解决方案,它不适合我,

多年来,我不以上述方式编写代码,而是在创建group时,我也会将groups表与groups_users表连接到users表,并在group对象中创建一个类似用户对象的数组(从不使用/触摸user类):

代码语言:javascript
复制
class Group {
    public $type;
    public $schedule;
    public $users;

    public function __construct($group_id) {
        $result = Query the `groups` table, joining the `groups_users` table,
                    **and also joining the `users` table,**
                    where `group_id` = $group_id
        $this->type = $result['type'];
        $this->schedule = $result['schedule'];

        foreach ($result['users'] as $user) {
            // Make user arrays
            $users[] = array_of_user_data_crafted_from_the_query_result;
        }
    }
}

当然,如果我创建了一个“...but”类,那么在它的构造函数中,我需要将communities表与communities_groups表与groups表与groups_users表与users表连接起来。

如果我创建了一个“...and”类,那么在它的构造函数中,我需要将cities表与cities_communities表与communities表与communities_groups表与groups表与groups_users表与users表连接起来。

多大的灾难啊!

,我必须在漂亮的OOP代码和100万次查询VS之间进行选择。1为每个超集手工查询和编写这些联接?没有任何系统可以自动实现这一点吗?

我正在使用CodeIgniter,并查看无数其他MVC,以及构建在其中的项目,如果不使用我概述的两种有缺陷的方法之一,就找不到任何人使用模型的一个好例子。

这似乎从来没有这样做过。

我的一位同事正在编写一个框架,该框架就是这样做的--创建一个包含数据模型的类。另外,高级模型可以包含单个模型的,并且它设计并自动化表连接以创建包含低级模型的对象实例化的高级模型,所有这些都是在一个单查询e 241中创建的。他声称,他以前也从未见过这样做的框架或系统。

请注意:我确实经常使用单独的类来实现逻辑和持久性。(VOs和DAOs -这是MVC的全部要点)。为了简单起见,为了简单起见,我只是在这个思想实验中将两者结合在一起,而不是一个类似MVC的架构。请放心,不管逻辑和持久性的分离,这个问题仍然存在。我相信,詹姆斯在下面这个问题的评论中向我介绍的这篇文章似乎表明,我提出的解决方案(我已经跟踪了多年)实际上是开发人员目前为解决这个问题所做的事情。然而,这个问题是试图找到自动化的确切解决方案的方法,因此它并不总是需要对每个超集进行手工编码。据我所见,这从来没有用PHP做过,我的同事的框架将是第一个这样做的,除非有人能指点我这样做。

而且,当然,我从不在构造函数中加载数据,我只调用我在实际需要数据时创建的load()方法。然而,这与这个问题无关,就像在这个思想实验中(以及在我需要自动化这个问题的现实生活中),我总是需要急切地--加载所有子集合的数据--尽可能远地加载,并且而不是--根据需要在将来的某个时间点加载它们。思想实验是简洁的--它没有遵循最佳实践,这是一个毫无意义的问题,试图解决其布局的答案也同样漏掉了重点。

编辑:为了清晰起见,这里是一个数据库模式。

代码语言:javascript
复制
CREATE TABLE `groups` (
  `group_id` int(11) NOT NULL,  <-- Auto increment
  `make` varchar(20) NOT NULL,
  `model` varchar(20) NOT NULL
)

CREATE TABLE `groups_users` ( <-- Relational table (many users to one group)
  `group_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL
)


CREATE TABLE `users` (
  `user_id` int(11) NOT NULL, <-- Auto increment
  `name` varchar(20) NOT NULL,
  `height` int(11) NOT NULL,
)

(还请注意,我最初使用了wheels和cars的概念,但这是愚蠢的,这个示例要清楚得多。)

解决方案:

最后,我找到了一个PHP ORM,它正是这样做的。是拉勒维尔的口才。您可以指定模型之间的关系,并且它智能地构建优化查询,以便使用如下语法进行急切加载:

代码语言:javascript
复制
Group::with('users')->get();

它是一个绝对的救生者。我还没写过一条查询。它也不使用联接,它聪明地编译和选择基于外键。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-22 02:38:02

Rails中的ActiveRecord实现了延迟加载的概念,即将数据库查询推迟到实际需要数据。因此,如果实例化一个my_car = Car.find(12)对象,它只查询cars表中的一行。如果稍后您想要my_car.wheels,那么它将查询want表。

我对上面的伪代码的建议是,不要加载构造函数中所有相关的对象。汽车构造函数应该只查询汽车,并且应该有一种方法来查询它的所有车轮,另一种方法应该查询它的经销商,它只查询经销商,延迟收集所有其他经销商的汽车,直到您特别地说出类似于my_car.dealership.cars的话

Postscript

ORM是数据库抽象层,因此必须对它们进行调优,以便于查询,而不是微调。它们允许您快速构建查询。如果稍后您决定需要微调查询,那么您可以切换到发出原始sql命令,或者尝试以其他方式优化要获取的对象的数量。当您开始进行性能调优时,这是Rails中的标准实践--查找在发出原始sql时效率更高的查询,并寻找避免在需要对象之前加载对象(与延迟加载相反)的方法。

票数 2
EN

Stack Overflow用户

发布于 2013-11-22 02:26:24

通常,我建议有一个有效地接受查询行的构造函数,或者更大的查询的一部分。如何做到这将取决于您的ORM。这样,您就可以获得高效的查询,但也可以在事实发生之后构造其他模型对象。

一些ORMs (django的模型,我相信一些ruby )试图在如何构造查询方面变得聪明,并且可能能够为您自动化这一点。诀窍是找出什么时候需要自动化。我对PHP ORMs不熟悉。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20135765

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档