8

我有一个名为 的表Cat和一个名为 的 PHP 类Cat。现在我想CatDataMapper上课,所以Cat extends CatDataMapper.

我希望 Data Mapper 类能够提供执行 ORM 以及创建、编辑和删除 Cat 的基本功能。

为此,也许非常了解这种模式的人可以给我一些有用的建议?我觉得只提供一些像update()、delete()、save()这样的函数有点太简单了。

我意识到 Data Mapper 有这个问题:首先创建 Cat 的实例,然后初始化所有变量,如 name、furColor、eyeColor、purrSound、meowSound、attendants 等。一切都设置好后,调用 save( ) 从 CatDataMapper 继承的函数。这很简单 ;) 但是现在,真正的问题是:您查询数据库中的猫并返回一个包含大量猫数据的简单无聊的结果集。

PDO 具有一些 ORM 功能来创建 Cat 实例。可以说我使用它,或者甚至可以说我有一个带有关联数组的 mapDataset() 函数。然而,一旦我从数据集中获得了我的 Cat 对象,我就有了冗余数据。同时,20 个用户可以从数据库中获取相同的猫数据并编辑猫对象,即重命名猫,然后 save() 它,而另一个用户仍然在设置另一个 furColor。当他们所有人都保存编辑时,一切都搞砸了。

呃......好吧,让这个问题很简短:这里有什么好的做法?

4

5 回答 5

12

来自PoEA 中的 DataMapper

数据映射器是将内存中的对象与数据库分开的软件层。它的职责是在两者之间传输数据,并将它们彼此隔离。使用 Data Mapper,内存中的对象甚至不需要知道是否存在数据库;他们不需要 SQL 接口代码,当然也不需要数据库模式的知识。(数据库模式总是不知道使用它的对象。)由于它是 Mapper (473) 的一种形式,因此 Data Mapper 本身对于领域层来说甚至是未知的。

因此,Cat 不应该扩展 CatDataMapper,因为这会创建一个 is-a 关系并将 Cat 绑定到 Persistence 层。如果您希望能够以这种方式处理 Cats 的持久性,请查看ActiveRecord或任何其他数据源架构模式。

使用域模型时通常使用 DataMapper。一个简单的 DataMapper 只会在字段到字段的基础上将数据库表映射到等效的内存类。但是,当需要 DataMapper 时,通常不会有这么简单的关系。表格不会 1:1 映射到您的对象。相反,多个表可以形成一个对象聚合,反之亦然。因此,实现CRUD 方法很容易成为相当大的挑战。

除此之外,它是更复杂的模式之一(涵盖 PoEA 中的 15 页),通常与Repository 模式等结合使用。查看本页右侧的相关问题列,了解类似问题。

至于您关于多个用户编辑同一个 Cat 的问题,这是一个常见的问题,称为Concurrency。一种解决方案是锁定该行,而有人对其进行编辑。但就像所有事情一样,这可能会导致其他问题

于 2009-12-28T18:16:02.670 回答
2

如果你依赖像DoctrinePropel这样的 ORM ,基本原则是创建一个静态类,该类将从数据库中获取实际数据(例如 Propel 将创建 CatPeer),然后 Peer 类检索到的结果将是“水合”到 Cat 对象中。

水合过程是将“普通无聊”的 MySQL 结果集转换为具有 getter 和 setter 的漂亮对象的过程。

因此,对于检索,您将使用类似CatPeer::doSelect(). 然后对于一个新对象,您首先要实例化它(或从数据库中检索和实例化): $cat = new Cat();

插入就像做一样简单:$cat->save();这相当于插入(或者如果对象已经存在于数据库中,则更新...... ORM应该知道如何通过使用来区分新对象和现有对象,因为例如,存在或不存在主键)。

于 2009-12-28T18:11:54.817 回答
2

在 PHP < 5.3 中实现数据映射器非常困难,因为您无法读取/写入受保护/私有字段。加载和保存对象时有几个选择:

  1. 使用某种解决方法,比如序列化对象,修改它的字符串表示,然后用 unserialize 把它带回来
  2. 公开所有字段
  3. 保持它们私有/受保护,并为它们中的每一个编写修改器/访问器

第一种方法有可能因新版本而中断,并且是非常粗暴的hack,第二种方法被认为是(非常)糟糕的做法。

第三个选项也被认为是不好的做法,因为您不应该为所有字段提供 getter/setter,而只为需要它的字段提供 getter/setter。从纯 DDD(领域驱动设计)的角度来看,您的模型会“损坏”,因为它包含仅因持久性机制而需要的方法。这也意味着现在您必须在字段 -> 表列旁边为字段 -> 设置方法描述另一个映射。

PHP 5.3 通过使用反射引入了访问/更改所有类型字段的能力:

http://hu2.php.net/manual/en/reflectionproperty.setaccessible.php

有了这个,您可以实现真正的数据映射器,因为不再需要为所有字段提供 mutators。

于 2009-12-29T01:51:25.203 回答
1

PDO 具有一些 ORM 功能来创建 Cat 实例。可以说我使用它,或者甚至可以说我有一个带有关联数组的 mapDataset() 函数。然而,一旦我从数据集中获得了我的 Cat 对象,我就有了冗余数据。同时,20 个用户可以从数据库中获取相同的猫数据并编辑猫对象,即重命名猫,然后 save() 它,而另一个用户仍然在设置另一个 furColor。当他们所有人都保存编辑时,一切都搞砸了。

为了跟踪数据的状态,通常会使用 IdentityMap 和/或 UnitOfWork 来跟踪映射实体上的所有不同操作……然后在请求周期结束时执行所有操作。

于 2009-12-28T18:19:20.480 回答
0

保持简短的回答:你有一个 Cat 的实例。(也许它扩展了 CatDbMapper 或 Cat3rdpartycatstoreMapper)你调用:

$cats = $cat_model->getBlueEyedCats();
//then you get an array of Cat objects, in the $cats array

不知道你用什么,你可以看看一些php框架来更好的理解。

于 2009-12-28T17:52:34.347 回答