【问题标题】:Best Practice approach to relating MySQL join queries to OOP and Objects将 MySQL 连接查询与 OOP 和对象相关联的最佳实践方法
【发布时间】:2012-11-11 20:42:24
【问题描述】:

我正在开发一个 PHP Web 应用程序,用户可以在其中创建目的地旅行,并邀请其他用户参加这些旅行。

我有DestinationsTripsUsers 的MySql 表,以及一个名为Invites 的表来解决UsersTrips 之间的多对多关系。

对于这些表中的每一个,我在我的应用程序中创建了一个类(所以Destinations 是一个类,Trips 是一个类,等等)。我为这些类中的每一个都编写了一个静态函数,它使对象能够被实例化并从 MySQL 查询中分配它们的属性(因此从SELECT * 查询返回的每一行都会导致一个对象被实例化并分配属性)。

我正在尝试创建一个页面,我的用户可以在其中查看他们计划的所有旅行的详细信息。此页面将显示目的地(来自Destinations)、旅行详情(例如来自Trips 的日期)和他们邀请的用户的详细信息(例如来自Users 的用户名)并将所有这些数据放在一个html中每个行程都是一行的表格。

为了实现这一点,到目前为止,我一直在实例化与用户的 user_idDestinationsInvites 相关的 Trips,这与 Trips 相关,以及与 Users 相关的 Users 987654339@。然后,我根据需要使用嵌套的 foreach 循环来显示它们,如下所示:

foreach($trips as $trip) {
 foreach($invites as $invite) {
   foreach($invited_users as $invited_user) {
      if($invite->trip_id == $trip->id && $invite->guest_id == $invited_user->id) {
        echo $invited_user->name;
                  } } } }

我可以看到这是可怕的,没有办法做到这一点。

通过阅读,我想我想使用 MySQL 来连接 4 个表,然后只选择与我的相关旅行相关的数据。我不确定的是:

a) 我如何从这个 MySQL 结果中实例化对象并正确分配它们的属性?

b) 即使这样做了,我如何避免昂贵的foreach 循环以在正确的行程旁边显示正确的数据?

是否有“最佳实践”方式以面向对象的方式显示来自多个相关数据库表的数据?

【问题讨论】:

  • 2 个非常有用的答案 - 非常感谢。

标签: php mysql oop join relational-database


【解决方案1】:

首先,“良好做法”是人们用来为自己的偏见披上可敬外衣的短语之一。最好询问如何通过设计实现特定目标。

话虽如此:您在将 RDBMS 映射到面向对象的系统时遇到了一个常见问题。谷歌“延迟加载”进行大量讨论。问题归结为您在任何时候加载多少“关系”的问题。在您的示例中,旅行与目的地和用户相关联;加载“旅行”时,您是否还应该加载目的地和用户?如果你这样做了,你是否还应该为用户加载其他信息(例如他们正在进行的其他旅行?)。如果你这样做了,你会加载用户所有行程的行程数据吗?等等——如果你不小心,你最终会加载整个数据库。

不加载所有相关实体的缺点是,如果一次加载每个对象的数据,性能会变得很差。

有关我认为最佳实践的详细说明,请购买并阅读 Evans 的“领域驱动设计”。

作为捷径,考虑创建一个“存储库”层,它知道如何将数据库记录映射到对象,并创建自定义方法来搜索您想要的内容。例如,您可以调用:

$repository::getTripsForUser($userID);

该方法将执行将 4 个表连接在一起的 SQL 查询,并将结果转换为对象树。

您可能希望利用其他人在解决此问题时所做的工作;有许多“对象关系映射”框架可以解决这个问题。我认为 ORM 解决方案是否让生活更轻松尚无定论 - 但值得一看。

【讨论】:

  • 内维尔对此表示感谢。我已经将 Doctrine 视为一个 ORM,但仍在争论它是否会对我有很大帮助。还阅读了似乎与此问题有关的对象关系阻抗不匹配。一些非常有用的东西要查找 - 欣赏它。
【解决方案2】:

我认为你把事情复杂化了,你不需要一次加载所有数据。

为什么要遍历所有个行程,而您需要显示一个用户的行程?

一种天真的但简单的 OOP 方法:一个 User 类,其中包含一个检索用户相关行程的方法。

它可以返回一个Trip 的数组,其中包含受邀用户的引用:

class User {
    private $id;
    public function __construct($id) {
        $this->id = $id;
    }
    public function getTrips() {
        $trips = array();
        // Run your query using $this->id to build the WHERE clause
        return $trips;
    }
}

class Trip {

    // Array of User objects invited to the trip        
    private $invited = array();

    // Other methods here to add/retrieve invited users

}

$user = new User(1);
foreach ($user->getTrips() as $trip) {
    // Do something with $trip
}

理想情况下,User 实例将存储在会话中

【讨论】:

  • 我喜欢它 - 谢谢。这更有意义 - 也将函数放回更符合 OOP 的类中。我唯一要担心的是,每次“旅行”都会获得受邀用户的数据库是否会有大量查询?
  • 这只是一个例子。在getTrips() 方法中,您可以在Trips + Invitees + User 之间创建一个JOIN,以在一个查询中构建完整的Trip 实例。如果这有帮助,可能会将问题标记为已接受? :-p
猜你喜欢
  • 1970-01-01
  • 2011-12-17
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 2011-03-19
  • 2021-09-24
  • 2011-03-29
  • 2011-04-14
相关资源
最近更新 更多