31

你对教义有什么经验?我从来都不是那种 ORM 的人,我主要使用一些基本的数据库抽象层(如 adodb)进行管理。

但我了解它的所有概念和好处。因此,当一个需要 ORM 的项目出现时,我想我会尝试其中一个 ORM 框架。

我必须在原则和推进之间做出决定,所以我选择了原则,因为我不想处理 phing 要求。

我不知道我做错了什么。我带着正确的心态进来了。而且我绝不是“初级” php 小子。但我一直在与系统作斗争。有很多文档,但感觉有点杂乱无章。像 YAML 这样简单的东西到 db 表创建是行不通的,只是在没有错误或任何东西的情况下失败。许多其他的东西有点时髦,需要在工作之前进行额外的调整。

也许我在这里做了一些愚蠢的新手假设,一旦我发现它是什么,我就会有一个哈哈的时刻。但现在我完全讨厌这个系统。

是否有任何人可以提供的一些提示,或者可能将我指向有关该主题的良好资源或有关此问题的一些权威网站/人?或者也许只是推荐另一个“正常工作”的 ORM 框架?

4

12 回答 12

47

我有复杂的感觉。我是 SQL 的大师,只是因为它很容易验证。您可以快速测试 SELECT 语句,直到获得正确的结果。重构是一件轻而易举的事。

在 Doctorine 或任何 ORM 中,有很多抽象层,几乎看起来像是强迫症(强迫症/强迫症)。在我尝试 Doctrine 的最新项目中,我遇到了几堵墙。我花了几天的时间才找到解决方案,我知道我可以在几分钟内用 SQL 编写。这太令人沮丧了。

我脾气暴躁。SQL 社区非常庞大。对 Doctrine 的社区/支持是微不足道的。当然,您可以查看源代码并尝试弄清楚……而这些问题需要几天时间才能弄清楚。

底线:不要尝试 Doctrine 或任何 ORM,而无需计划大量时间自行摸索。

于 2010-02-18T19:55:19.913 回答
12

我认为 mtbikemike 完美地总结了这一点:“我花了几天的时间才找到解决方案,我知道我可以在几分钟内用 SQL 编写。” 这也是我的经历。SAD(慢速应用程序开发)是有保证的。更不用说丑陋的代码和每个角落的限制。本来应该需要几分钟的事情需要几天的时间,而通常会更复杂并且需要几个小时或几天的事情是不可行的(或者不值得花时间)。生成的代码更加冗长和神秘(因为我们确实需要另一种查询语言 DQL 来降低可读性)。奇怪的错误无处不在,大部分时间都花在寻找它们并遇到限制和问题上。Doctrine(我只使用 v2.x)类似于徒劳的练习,绝对没有任何好处。它' 到目前为止,它是我当前系统中最讨厌的组件,也是唯一一个存在巨大问题的组件。进入一个新系统时,我总是在数据库和实体类之间来回切换,试图找出代码中不同位置的正确名称。一场彻头彻尾的噩梦。

我没有看到 Doctrine 的一个优点,只有缺点。我不知道它为什么存在,而且我每天都希望它不存在(至少在我的项目中)。

于 2014-05-29T14:52:43.450 回答
9

我们在 Symfony 中使用 Propel 已经 2 年了,在 Symfony 中使用 Doctrine 已经超过 1 年了。我可以说,使用 MVC 框架迁移到 ORM 是我们迈出的最好的一步。我建议坚持使用 Doctrine,尽管它需要一些时间来学习如何使用它。最后,您会发现您的代码更具可读性和灵活性。

如果您正在寻找从哪里开始,我会推荐 Symfony Jobeet 教程http://www.symfony-project.org/jobeet/1_4/Doctrine/en/(第 3、6 章涵盖基础知识)当然还有教义文件。

正如我在上面所写的,我们已经使用 Doctrine 有一段时间了。为了让我们的工作更舒适,我们开发了一个名为 ORM Designer (www.orm-designer.com) 的工具,您可以在其中在图形用户界面中定义 DB 模型(不再有 YAML 文件 :-),顺便说一句,这还不错)。您还可以找到一些有用的教程。

于 2010-01-11T22:30:15.880 回答
6

Propel and Doctrine 使用 PDO。PDO 在 Oracle 数据库中有很多未解决的错误。它们都与 CLOB 字段有关。如果您正在使用 Oracle,请在开始新项目之前记住这一点。这些错误自多年前就已开放。Doctrine 和 PDO 与 Oracle 和 CLOB 一起使用会崩溃

于 2010-02-24T09:43:05.803 回答
6

我的经历听起来和你的相似。我才刚刚开始使用教义,从未使用过 Propel。但是,我对教义非常失望。它的文档很糟糕。组织不善,而且相当不完整。

于 2010-01-19T20:24:51.060 回答
5

我在一个中型项目中使用 Doctrine,我必须从我不拥有的预先存在的数据库中工作。它为您提供了许多内置功能,但我有一个主要的抱怨。

由于我必须从数据库生成模型,反之亦然,因此我的模型与数据库太接近:字段的名称与数据库列的名称非常相似,要获取对象,您必须在基本的 sql 中查询(其中我应该放那个代码,我该如何测试它?)等。

最后,我不得不为教义编写一个复杂的包装器,这让我质疑如果只使用旧的 dao/model 方法并将教义排除在外,会不会更容易。陪审团仍然没有定论。祝你好运!

于 2009-07-29T11:50:30.870 回答
5

2015 年使用 Doctrine 2.5。看起来进展顺利。直到我想使用两个实体(在一个 JOIN 中)。[在我掌握了 DQL 之后现在好多了]

好的:

  • 为我生成 SQL
  • 使用外键和参照完整性
  • 默认情况下生成 InnoDB
  • 使用教义命令行工具对 SQL 进行的更新

好的:

  • 非常了解命名和映射以及如何命名以及如何将实体映射到实际表

坏的

  • 花费大量时间 - 学习查询生成器的自定义 API。或者弄清楚如何做一个简单的 JOIN,想知道是否有更好的技术。如果你想做面向对象的查询,简单的 JOIN 似乎需要编写自定义函数。
  • [更新上面的第一印象] -- 我选择使用 DQL,因为它与 SQL 最相似

在我看来,该工具在概念上很棒,但它的正确执行需要开发人员的大部分时间来参与。我很想将它用于实体 SQL 生成,然后将 PDO 用于实际输入/输出。只是因为我还没有学习如何使用 SQL 进行外键和参照完整性。但是学习这些似乎比学习 Doctrine 的来龙去脉要容易得多,即使是简单的东西,比如相当于 JOIN 的实体。

现有项目中的原则

我(刚刚开始)使用 Doctrine 在现有项目上开发新功能。因此,我没有为该功能添加新的 mysql 表,而是添加了实体(它使用 Doctrine 模式生成为我创建了表)。在我更好地了解它之前,我保留不将 Doctrine 用于现有表。

如果我要在现有表上使用它,我会首先...清理表,其中包括:

  • 添加作为主/代理键的 id 列
  • 使用 InnoDb/transaction-capable 表
  • 将其适当地映射到实体
  • 运行 Doctrine 验证工具 ( doctrine orm:validate-schema)

这是因为 Doctrine 对您的表格做出了某些假设。而且因为您本质上是要通过代码来驱动您的表格。因此,您的代码和表格必须尽可能以 1:1 的比例达成一致。因此,Doctrine 通常不适用于任何“自由格式”表格。

但是,您也许可以在某些情况下小心谨慎地摆脱一些小事情,例如在您的实体中没有考虑额外的列(除非您要求,否则我认为 Doctrine 不会检查)。您将必须知道您正在逃避什么来构建您的查询。即,当您请求一个整体的“实体”时,Doctrine 会专门通过列名请求实体的所有字段。如果您的实际架构包含更多列名,我认为 Doctrine 不会介意(它不会,因为我已经通过在我的架构中创建一个额外的列来验证)。

所以是的,可以使用 Doctrine,但我会从小处着手。首先,您很可能必须转换表以支持事务并拥有代理索引(主键)。对于诸如外键和参照完整性之类的事情,您必须使用 Doctrine 来完善您的实体并将它们完美匹配。您可能必须让 Doctrine 重新构建您的模式以使用其自己的索引名称,以便它可以正确使用 FK 和 RI。您基本上放弃了对 Doctrine 表的一些控制,所以我相信它必须以自己的方式了解架构(比如能够使用自己的索引名称等)。

于 2015-10-06T19:10:13.043 回答
5

聚会有点晚了,但让我把我的两分钱扔在这里。我将与Laravel建立联系,因为那是我使用的框架。

Active Record vs. 数据映射 vs. 正确的 OOP

Laravel 和许多其他框架都喜欢Active Record。它可能非常适合简单的应用程序,并且可以节省您进行琐碎的数据库管理的时间。但是,从 OOP 的角度来看,它是一种纯粹的反模式SoC(关注点分离)刚刚被杀死。它在模型属性和 SQL 列名之间创建耦合。对于扩展和未来的更新来说很糟糕。

随着您的项目增长(是的,它会!),ActiveRecord 将越来越痛苦。甚至不要轻易考虑更新 SQL 结构。请记住,您的 PHP 代码中都有列名。

我被聘为一个项目,该项目的目标是在未来变得相当大。我看到了 ActiveRecord 的局限性。我坐了 3 周,使用 Data Mapper 重写了所有内容,它将 DB 与上面的层分开。

现在,回到Data Mapper以及为什么我没有选择 Doctrine

Data Mapper的主要思想是,它将您的数据库与您的代码分开。从 OOP 的角度来看,这是正确的方法。SoC规则!我详细回顾了Doctrine,我立即不喜欢几个方面。

  • 映射。为什么在世界上会有人使用评论作为命令?我认为这是一个非常糟糕的做法。为什么不直接使用 PHP 类来存储映射关系呢?
  • 地图的 Yaml 或 XML。再次,为什么?当可以使用常规 PHP 类时,为什么要浪费时间解析文本文件。另外,一个类可以扩展、继承,可以包含方法,而不仅仅是数据。等等。
  • 如果我们有一个映射器和一个携带数据的模型,那么它应该是存储模型的映射器。诸如$product->save()ar 之类的方法并不好。模型处理数据,它不应该关心将任何内容存储到数据库中。这是一个非常紧密的耦合。如果我们花时间构建一个映射器,那么为什么不拥有$mapper->save($product). 根据定义,应该是映射器知道如何保存数据。

毫无疑问,Doctrine 或 Eloquent 等工具在开始时可以节省时间。但对于每个人来说,这是一个棘手的问题。/开发时间/未来更新/价格/简单性/遵循OOP原则/之间的正确妥协是什么?最后,由您来回答和正确决定。

我自己的 DataMapper 而不是 Doctrine

我最终开发了自己的 DataMapper,并且已经将它用于我的几个小项目。它工作得非常好,易于扩展和重用。大多数时候我们只是设置参数,不需要新代码。

以下是关键原则:

  • 模型携带数据,类似于 Laravel 的模型。以下示例的示例变量$model
  • ModelMap包含一个字段,该字段将 Model 的属性映射到 SQL 数据库中表的列。ModelMaps 知道表名、id 等。它知道哪些属性应该转换为json,哪些属性应该隐藏(例如deleted_at)。此 ModelMap 包含具有相同名称的列(连接表)的别名。示例变量:$modelMap.
  • ModelDataMapper是一个在控制器中接受ModelModelMap并提供 store/getById/deleteById 功能的类。您只需调用即可$modelMapper->store($model)
  • 基本 DataMapper 还处理分页、搜索能力、将数组转换为 json、添加时间戳、检查软删除等。对于简单的用法,基本 DataMapper 就足够了。对于更复杂的事情,使用继承很容易对其进行扩展。
于 2018-08-16T13:27:03.140 回答
4

在 2016 年使用 Doctrine ORM,大约有 2 - 2.5 年的经验。

固有的不一致

SELECT i, p            
FROM \Entity\Item i
JOIN i.product p
WHERE ...

假设实体是ItemProduct。它们通过 连接Item.product_idProduct.id,并Product包含Product.model我们要与 一起显示的内容Item

这是从数据库中检索相同的“product.model”,使用上述 SQL 但不同的 SQL 参数:

//SELECT i, p
$ret[0]->getProduct()->getModel();          

//SELECT i as item, p as product
$ret[0]['item']->getProduct()->getModel();  

//SELECT i as item, p.model as model
$ret[0]['model'];                           

我要说的是:

根据您编写 DQL/ORM SELECT 语句的方式,输出结果集结构可能会发生巨大变化

从对象数组到关联对象数组,再到关联数组数组,取决于您想要的方式SELECT。想象一下,您必须对 SQL 进行更改,然后想象必须回到您的代码并重新执行与从结果集中读取数据相关的所有代码。哎哟! 哎哟! 哎哟! 即使是几行代码,你也依赖于结果集的结构,没有完全的解耦/通用标准。

教义擅长什么

在某些方面,它消除了处理 SQL、制作和维护自己的表。这并不完美。有时它会失败,您必须转到 MySQL 命令行并键入 SQL 以将内容调整到 Doctrine 和您满意的位置,Doctrine 认为列类型有效的位置以及您对列类型满意的位置。您不必定义自己的外键或索引,它会自动为您完成。

教义不擅长什么

每当您需要将任何非常高级的 SQL 转换为 DQL/ORM 时,您都可能会遇到困难。除此之外,您还可以处理上述不一致的情况。

最后的想法

我喜欢 Doctrine 为我创建/修改表,将表数据转换为对象,并将它们持久化,并使用准备好的语句和其他检查和平衡,使我的数据更安全。

我喜欢 Doctrine 从 PHP 的面向对象接口中处理持久存储的感觉。我有一种刺痛的感觉,我可以将我的数据视为我的代码的一部分,而 ORM 负责处理与数据库交互的脏东西。数据库感觉更像是一个局部变量,我很感激如果你照顾好你的数据,它会爱你。

我讨厌 Doctrine,因为它的不一致和艰难的学习曲线,当我知道如何用 SQL 编写东西时,我不得不查找 DQL 的专有语法。SQL 知识很容易获得,DQL 没有那么多专家在野外,也没有积累的知识体系(与 SQL 相比)可以在您遇到困难时为您提供帮助。

于 2016-06-06T15:52:09.353 回答
3

我不是 Doctrine 方面的专家——我自己刚开始使用它,我不得不承认它的体验有点复杂。它对你有很大帮助,但如何告诉它做这个或那个并不总是很明显。

例如,当尝试将 YAML 文件与自动关系发现一起使用时,多对多关系没有正确转换为 php 模型定义。没有您提到的错误,因为它根本没有将其视为多对多。

我会说你可能需要时间来了解这种或那种做事方式以及元素如何相互作用。有时间一步一步地做事情是一件好事,并且在一种孤立的情况下一次一个地处理问题。一次尝试做太多事情可能会让人不知所措,并且可能会更难真正找到问题所在。

于 2009-05-08T22:02:33.347 回答
3

在对 PHP 的各种 ORM 库进行了一些研究之后,我决定使用 PHP ActiveRecord(请参阅)。我的决定归结为几乎没有配置、库的轻量级特性以及缺乏代码生成。教义对我的需要来说太强大了;PHP ActiveRecord 不能做什么我可以在我的包装层中实现。我建议花点时间检查一下您在 ORM 中的要求,看看是否有一个像 PHP ActiveRecord 这样的简单工具可以提供您需要的东西,或者家庭滚动的活动记录实现是否会更好。

于 2010-07-18T03:05:38.630 回答
0

现在我正在使用带有 Doctrine ORM 的 Symfony 框架,如何将 Doctrine 与普通查询一起使用?例如,来自 knpununiversity,我可以创建自定义存储库方法,例如:

     public function countNumberPrintedForCategory(Category $category)
    {
        $conn = $this->getEntityManager()
            ->getConnection();
        $sql = '
            SELECT SUM(fc.numberPrinted) as fortunesPrinted, AVG(fc.numberPrinted) as fortunesAverage, cat.name
            FROM fortune_cookie fc
            INNER JOIN category cat ON cat.id = fc.category_id
            WHERE fc.category_id = :category
            ';
        $stmt = $conn->prepare($sql);
        $stmt->execute(array('category' => $category->getId()));
        return $stmt->fetch();
... lines 30 - 37
    }

我只是使用 Doctrine Entities 来创建一个处理表单,当我需要更复杂的查询时,我只是做简单的语句并获取我需要的值,从这个例子中我也可以将实体作为变量传递并获取它的值来进行查询。我认为这个解决方案很容易理解,构建表单、为表单传递数据和编写复杂查询所需的时间更少,不像用 Doctrine 编写它们那么难。

于 2017-06-11T08:39:47.613 回答