您对Doctrine ORM的体验如何?

时间:2008-11-06 04:21:38

标签: php orm doctrine-orm doctrine

您对doctrine的体验是什么? 我从来都不是一个ORM类型的人,我主要管理像adodb这样的基本数据库抽象层。

但我了解它的所有概念和好处。所以当一个需要ORM的项目出现时,我认为我会尝试一个ORM框架。

我要在学说和推动之间做出决定,所以我选择了学说,因为我不想处理这个要求。

我不知道我做错了什么。我带着正确的心态进来了。我绝不是一个'初级'php小子。但是我每一步都在与系统作斗争。有很多文档,但都觉得有点混乱。而简单的东西,如YAML到数据库表创建只是不工作,只是没有错误或任何东西bork out。很多其他的东西都有点时髦,需要在工作之前进行额外的调整。

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

是否有人可以给出一些提示或者可能指向我关于这个主题或某个权威网站/人的关于此的良好资源?或者只是推荐另一个“正常工作”的ORM框架?

12 个答案:

答案 0 :(得分:42)

我的感情很复杂。我只是SQL的高手,因为它很容易验证。您可以快速测试SELECT语句,直到获得正确的结果。并且重构非常简单。

在Doctorine或任何ORM中,有如此多的抽象层,它几乎就像强迫症(强迫症/强迫症)。在我最近的项目中,我尝试了Doctrine,我打了几个墙。我花了几天时间才找到一个解决方案,我知道我可以在几分钟内用SQL编写。这太令人沮丧了。

我脾气暴躁。 SQL的社区是巨大的。社区/对学说的支持是微不足道的。当然你可以查看来源并尝试弄明白......这些问题需要花费数天的时间来解决。

结论:不要尝试使用Doctrine或任何ORM,而不需要花很多时间自己进行grokking。

答案 1 :(得分:10)

我认为mtbikemike完美地总结了这一点:"我花了几天时间才找到一个解决方案,我知道我可以在几分钟内用SQL编写。"那也是我的经历。 SAD(慢速应用程序开发)得到保证。更不用说每个角落都有丑陋的代码和限制。需要几分钟的事情需要几天时间,通常情况会更复杂,花费数小时或数天的事情是不可行的(或者不值得花时间)。由此产生的代码更加冗长和含糊不清(因为我们确实需要另一种查询语言DQL,以使事情更具可读性)。奇怪的虫子四处都是,大部分时间都花在追捕它们并遇到限制和问题。学说(我只使用v2.x)类似于徒劳无功,完全没有任何好处。它是我目前系统中最讨厌的组件,也是唯一一个存在巨大问题的组件。进入一个新的系统,我总是来自db到实体类,试图找出代码中不同位置的哪个名称是正确的。一场噩梦。

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

答案 2 :(得分:9)

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

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

正如我上面所写的那样,我们一直在使用Doctrine一段时间了。为了使我们的工作更加舒适,我们开发了一个名为ORM Designer(www.orm-designer.com)的工具,您可以在图形用户界面中定义数据库模型(不再是YAML文件:-),这些文件根本不是坏事。 )。你也可以找到一些有用的教程。

答案 3 :(得分:6)

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

答案 4 :(得分:5)

Propel和Doctrine使用PDO。 PDO在Oracle数据库中存在许多漏洞。所有这些都与CLOB字段有关。如果您正在使用Oracle,请在开始新项目之前牢记这一点。这些漏洞几年前就开放了。 Doctrine和PDO将崩溃使用Oracle和CLOB

答案 5 :(得分:4)

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

由于我必须从数据库生成我的模型而不是反之亦然,我的模型离数据库太近了:字段与数据库列的名称非常相似,以获取必须查询的对象sql(我在哪里放这些代码,我该如何测试?)等等。

最后,我不得不为教条编写一个复杂的包装器,这让我怀疑是不是更容易使用旧的dao / model方法并将学说放在图片之外。陪审团仍在讨论这个问题。祝你好运!

答案 6 :(得分:4)

2015年使用Doctrine 2.5。它似乎进展顺利。直到我想使用两个实体(在JOIN中)。 [在我掌握了DQL之后,它现在变得更好]

好:

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

好:

  • 对命名和映射具有超级意识,以及如何命名以及如何将实体映射到实际表格

糟糕

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

在我看来,该工具在概念上很出色,但其正确的执行需要开发人员的大部分时间。我很想将它用于实体SQL生成,但随后将PDO用于实际的输入/输出。只是因为我还没有学习如何用SQL做外键和参照完整性。但是学习这些似乎比学习Doctrine ins and out更容易,即使是简单的东西,比如一个等同于JOIN的实体。

现有项目中的原则

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

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

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

这是因为Doctrine对您的表做出了某些假设。而且因为你实际上是通过代码来驱动你的表。因此,您的代码和表格必须尽可能达到1:1的协议。因此,Doctrine不适合任何"自由形式"一般来说。

然而,你可能会,在某些情况下,你可以通过一些小的东西,比如在你的实体中没有考虑额外的列来逃避(我认为除非你要求,否则我不认为Doctrine会检查) 。您必须构建查询知道您正在逃避的内容。即当你要求一个"实体"作为一个整体,Doctrine特别通过列名请求实体的所有字段。如果您的实际架构包含更多列名称,我不会认为Doctrine会介意(它没有,因为我已通过在架构中创建额外列来验证)。

所以是的,可以使用Doctrine,但我从小开始就小心翼翼。您很可能必须将表转换为支持事务并具有代理索引(主键)。对于像外键和参照完整性这样的东西,你必须与Doctrine一起完善抛光你的实体并完美匹配它们。您可能必须让Doctrine重新构建您的架构以使用它自己的索引名称,以便它可以正确使用FK和RI。你实际上放弃了对Doctrine的一些控制,所以我相信它必须以自己的方式知道模式(比如能够使用自己的索引名称等)。

答案 7 :(得分:3)

我不是Doctrine的专家 - 我自己开始使用它,我不得不承认它有点混合体验。它为你做了很多,但并不总是很明显地告诉它如何做到这一点。

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

我想说你可能需要时间来了解这种或那种做事方式以及元素如何相互作用。并且有时间一步一步地做事情将是一件好事,并且在某种程度上孤立地处理问题。试图一次做太多事情可能会让人感到压倒一切,并且可能会让实际找到错误的地方变得更加困难。

答案 8 :(得分:3)

在对PHP的各种ORM库进行一些研究之后,我决定使用PHP ActiveRecord。我的决定归结为图书馆几乎没有配置,轻量级特性以及缺乏代码生成。学说对我所需要的东西来说太强大了; PHP ActiveRecord没有做什么我可以在我的包装层实现。我建议花点时间检查一下ORM中你的要求是什么,看看像PHP ActiveRecord这样的简单提供你需要的东西,或者如果一个自制的活动记录实现会更好。

答案 9 :(得分:3)

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

活动记录与数据映射与适当的OOP

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

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

我被录用了一个项目,该项目的目标是在未来发展。我看到了ActiveRecord的局限性。我坐了三个星期,然后使用数据映射器重写了所有内容,该数据映射器将数据库与上面的层分开。

现在,返回到数据映射器为什么我没有选择“学说”

数据映射器的主要思想是,它将数据库与代码分开。从OOP角度来看,这是正确的方法。 SoC规则!我详细审查了《学说》 ,但我立即不喜欢其中的几个方面。

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

毫无疑问,诸如Doctrine或Eloquent之类的工具在开始时就节省了时间。但是,这是每个人都面临的棘手问题。 /开发时间/未来更新/价格/简单性/遵循OOP原则/之间的正确妥协是什么?最后,由您自己决定并做出正确的决定。

我自己的DataMapper而不是Doctrine

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

以下是关键原则:

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

答案 10 :(得分:1)

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

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

//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'];                           

我正在制作的是:

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

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

什么学说擅长什么

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

什么学说不好

每当您需要将任何显着高级的SQL转换为DQL / ORM时,您可能会感到困难。除此之外,您还可以处理上述不一致的问题。

最后的想法

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

我喜欢Doctrine在PHP的面向对象界面中处理持久存储的感觉。我觉得我可以认为我的数据是我代码的一部分,并且ORM负责处理与数据库交互的脏东西。数据库感觉更像是一个局部变量,我已经获得了一个赞赏,如果你照顾你的数据,它会爱你。

我讨厌Doctrine的不一致和严峻的学习曲线,当我知道如何在SQL中编写内容时,必须查找DQL的专有语法。 SQL知识随时可用,DQL没有那么多专家,也没有积累的知识体系(与SQL相比)可以帮助你解决问题。

答案 11 :(得分:0)

目前我正在使用Sytrfony框架和Doctrine ORM, 如何将Doctrine与简单查询一起使用? 对于例如来自knpuniversity,我可以创建自定义存储库方法,如:

     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编写它们那么难。