【问题标题】:Zend framework - Why should I use data mapper / Db_Table_Row?Zend 框架 - 为什么我应该使用数据映射器/Db_Table_Row?
【发布时间】:2011-06-18 03:19:15
【问题描述】:

扩展问题:我为什么要使用数据映射器/Db_Table_Row,因为 DbTable 能够处理数据操作的大部分基本任务。

我目前正在学习 ZF v1.11

对于数据库操作,我为每个表创建了 DbTable。例如,“users”表由 Application_Model_DbTable_Users 表示,其中没有其他代码。

在操作数据时,我可以使用:

<?php
$uTable = new Application_Model_DbTable_Users();
$newUid = $uTable->insert(array('name'=>'Old Name', 'email'=>''));
$user = $uTable->find($newUid)->current();

// Then I can use $user which is instance of Table_Row
$user->name = "New Name";
$user->email = "email@addr.com";
$user->save();

我的问题是,我什么时候需要定义一个行类(假设 Table_Row 在 ZF-Tutorials 中被称为 DataMapper)

// By, adding this to the DbTable class
protected $_rowClass = 'Application_Model_User';

为每个实体使用 Row 类有什么好处?谁能指出我的最佳做法。

【问题讨论】:

标签: php database design-patterns zend-framework zend-db-table


【解决方案1】:

您不需要定义自己的 Table_Row。但是,它在许多情况下可能很有用,特别是如果您想为给定的用户行定义一些特定的方法或属性。它们还可以提高代码的可读性。

例如在您的用户表案例中,您可以在自定义用户行中定义一个名为 getFullName() 的方法:

public function getFullName() {
    return $this->firstName . ' ' . $this->lastName;
}

那么当你获取用户行对象时,要获取用户的全名,你就这样做:

$user = $uTable->find($newUid)->current();
$fullName = $user->getFullName();

第二个例子是当您有一些父表到用户表时,例如地址。在这种情况下,您可以在用户行中定义一个名为 getAddress 的方法:

public function getAddress() {
    return $this->findParentRow('Application_Model_DbTable_Addresses');
}

在这种情况下,您将获得当前用户的地址行对象,如下所示:

$user = $uTable->find($newUid)->current();
$addressRow = $user->getAddress();

另一个例子,当您想要创建自定义删除或插入方法时。假设您要确保不想使用 delete() 方法删除管理员用户。然后你可以重载 Zend_Db_Table_Row 中的 delete 方法,如下所示:

public function delete() {
        if ('admin' === $this->userRole) {
              return 0;
        }
        return parent::delete();
} 

这样,您将无法仅通过在用户行对象上调用 delete() 来删除管理员用户:

 $user = $uTable->find($newUid)->current();
 $rowsDeleted = $user->delete(); // would be 0 if $user is admin

这只是三个基本示例,展示了定义自己的行类的有用性。但当然它们不是必需的。但是,根据我自己的经验,它们非常方便。

【讨论】:

  • 在问题#373054 的答案中,有一个用于用户的函数 sendMailTo,在 Db_Row 类中保留与数据库无关的函数是一个好习惯吗?这些特定于用户的业务逻辑应该放在哪里?
  • @侯赛因汗。事实上,Bill Karwin 呈现的是您自己的 Person 类,其中包含与人相关的业务逻辑。请注意,Person 类不扩展任何类。此类的构造函数可能会采用 My_Db_Table_Row_Person 类的实例或人员的 id。您可以将其视为一个新的抽象层,仅特定于您放置业务逻辑的项目,例如发送电子邮件。顺便说一句,Bill Karwin 实际上致力于 Zend_Db 的开发 :)。
【解决方案2】:

简而言之:这是关于隔离。

Zend_Db_Table 是表数据网关的实现。它通过一个类引导对特定表视图的 CRUD 访问。它通常与Table Module 一起使用,例如一个类,其中包含网关处理的记录的业务逻辑。

Zend_Db_Table_RowRow Data Gateway Pattern 的实现。在这里,返回的对象看起来与数据库记录完全一样,它们包含处理该数据的业务逻辑,但它们不包含使用它们来自的表(即 ActiveRecord)进行 CRUD 的逻辑,而是聚合它们。

只要您没有太多 object relational impedance mismatch,行数据网关就可以了。对象在关系数据库中的持久化方式和它在对象世界中的外观通常是完全不同的事情。使用Domain Model 时,您的业务对象的结构通常与它们存储在数据库中的方式不同。因此,您不能轻易地从数据库中对它们进行 CRUD。这就是DataMapper 发挥作用的地方。

DataMapper 负责将域对象映射到记录集,反之亦然。这使您的应用程序更易于维护,因为它将您的域对象与数据库结构分离。它使它们保持分离,并为您在如何对两个层(持久性和域)建模时提供更大的灵活性。

【讨论】:

    猜你喜欢
    • 2011-11-29
    • 2011-10-05
    • 2011-06-14
    • 1970-01-01
    • 2011-03-22
    • 2012-01-31
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    相关资源
    最近更新 更多