What's your experience with Doctrine ORM? [clo

2019-03-12 01:21发布

问题:

What's your experience with doctrine? I've never been much of an ORM kind of guy, I mostlymanaged with just some basic db abstraction layer like adodb.

But I understood all the concepts and benifits of it. So when a project came along that needed an ORM I thought that I'd give one of the ORM framework a try.

I've to decide between doctrine and propel so I choose doctrine because I didn't want to handle the phing requirement.

I don't know what I did wrong. I came in with the right mindset. And I am by no means a 'junior' php kiddie. But I've been fighting the system each step of the way. There's a lot of documentation but it all feels a little disorganize. And simple stuff like YAML to db table creation just wouldn;t work and just bork out without even an error or anything. A lot of other stuff works a little funky require just that extra bit of tweaking before working.

Maybe I made some soft of stupid newbie assumption here that once I found out what it is I'll have the aha moment. But now I'm totally hating the system.

Is there maybe some tips anyone can give or maybe point me to a good resource on the subject or some authoritative site/person about this? Or maybe just recommend another ORM framework that 'just works"?

回答1:

I have mixed feelings. I am a master at SQL only because it is so easy to verify. You can test SELECT statements quickly until you get the results right. And to refactor is a snap.

In Doctorine, or any ORM, there are so many layers of abstraction it almost seems OCD (obsessive/compulsive). In my latest project, in which I tried out Doctrine, I hit several walls. It took me days to figure out a solution for something that I knew I could have written in SQL in a matter of minutes. That is soooo frustrating.

I'm being grumpy. The community for SQL is HUGE. The community/support for Doctrine is minuscule. Sure you could look at the source and try to figure it out ... and those are the issues that take days to figure out.

Bottom line: don't try out Doctrine, or any ORM, without planning in a lot of time for grokking on your own.



回答2:

I think mtbikemike sums it up perfectly: "It took me days to figure out a solution for something that I knew I could have written in SQL in a matter of minutes." That was also my experience. SAD (Slow Application Development) is guaranteed. Not to mention ugly code and limitations around every corner. Things that should take minutes take days and things that would normally be more complicated and take hours or days are just not doable (or not worth the time). The resulting code is much more verbose and cryptic (because we really need another query language, DQL, to make things even less readable). Strange bugs are all around and most of the time is spent hunting them down and running into limitations and problems. Doctrine (I only used v2.x) is akin to an exercise in futility and has absolutely no benefits. It's by far the most hated component of my current system and really the only one with huge problems. Coming into a new system, I'm always going back and forth from the db to the entity classes trying to figure out which name is proper in different places in the code. A total nightmare.

I don't see a single pro to Doctrine, only cons. I don't know why it exists, and every day I wish it didn't (at least in my projects).



回答3:

we have been using Propel with Symfony for 2 years and Doctrine with Symfony for more than 1 year. I can say that moving to ORM with MVC framework was the best step we've made. I would recommend sticking with Doctrine eventhough it takes some time to learn how to work with it. In the end you'll find your code more readable and flexible.

If you're searching for some place where to start, I would recommend Symfony Jobeet tutorial http://www.symfony-project.org/jobeet/1_4/Doctrine/en/ (chapters 3, 6 covers the basics) and of course Doctrine documentation.

As I wrote above we have been using Doctrine for some time now. To make our work more comfortable we developed a tool called ORM Designer (www.orm-designer.com) where you can define DB model in a graphical user interface (no more YAML files :-), which aren't btw bad at all). You can find there also some helpful tutorials.



回答4:

My experiences sound similar to yours. I've only just started using doctrine, and have never used Propel. However I am very disapointed in Doctrine. It's documentation is terrible. Poorly organised, and quite incomplete.



回答5:

Propel and Doctrine uses PDO. PDO has a lot of open bugs with the Oracle Database. All of them related with CLOB fields. Please keep this in mind before starting a new project if you are working with Oracle. The bugs are open since years ago. Doctrine and PDO will crash working with Oracle and CLOBs



回答6:

I'm using Doctrine in a medium sized project where I had to work from pre-existing databases I don't own. It gives you alot of built in features, but I have one major complaint.

Since I had to generate my models from the databases and not vice-versa, my models are too close to the database: the fields have very similar names to the database columns, to get objects you have to query in what is essential sql (where do I put that code, and how do I test it?), etc.

In the end I had to write a complex wrapper for doctrine that makes me question if it wouldn't have been easier to just use the old dao/model approach and leave doctrine out of the picture. The jury is still out on that. Good luck!



回答7:

Using Doctrine 2.5 in 2015. It was seemingly going well. Until I wanted to use two entities (in a JOIN). [it's better now after I got a hang of DQL]

Good:

  • generating SQL for me
  • use of Foreign Keys and Referential Integrity
  • InnoDB generation by default
  • updates made to SQL with doctrine command line tool

Okay:

  • being hyper-aware of naming and mapping and how to name and how to map entities to actual tables

The Bad

  • takes a lot of time - learning custom API of query builder. Or figuring out how to do a simple JOIN, wondering if better techniques are out there.. Simple JOINs seem to require writing custom functions if you want to do object oriented queries.
  • [update on first impression above] -- I chose to use DQL as it is most similar to SQL

It seems to me that the tool is great in concept but its proper execution desires much of developer's time to get onboard. I am tempted to use it for entity SQL generation but then use PDO for actual Input/Output. Only because I didn't learn yet how to do Foreign Key and Referential Integrity with SQL. But learning those seems to be much easier task than learning Doctrine ins and outs even with simple stuff like a entity equivalent of a JOIN.

Doctrine in Existing Projects

I (am just starting to) use Doctrine to develop new features on an existing project. So instead of adding new mysql table for example for the feature, I have added entities (which created the tables for me using Doctrine schema generation). I reserve not using Doctrine for existing tables until I get to know it better.

If I were to use it on existing tables, I would first ... clean the tables up, which includes:

  • adding id column which is a primary/surrogate key
  • using InnoDb/transaction-capable table
  • map it appropriately to an entity
  • run Doctrine validate tool (doctrine orm:validate-schema)

This is because Doctrine makes certain assumptions about your tables. And because you are essentially going to drive your tables via code. So your code and your tables have to be in as much as 1:1 agreement as possible. As such, Doctrine is not suitable for just any "free-form" tables in general.

But then, you might be able to, with some care and in some cases, get away with little things like an extra columns not being accounted for in your entities (I do not think that Doctrine checks unless you ask it to). You will have to construct your queries knowing what you are getting away with. i.e. when you request an "entity" as a whole, Doctrine requests all fields of the entity specifically by column name. If your actual schema contains more column names, I don't think Doctrine will mind (It does not, as I have verified by creating an extra column in my schema).

So yes it is possible to use Doctrine but I'd start small and with care. You will most likely have to convert your tables to support transactions and to have the surrogate index (primary key), to start with. For things like Foreign Keys, and Referential Integrity, you'll have to work with Doctrine on polishing your entities and matching them up perfectly. You may have to let Doctrine re-build your schema to use its own index names so that it can use FK and RI properly. You are essentially giving up some control of your tables to Doctrine, so I believe it has to know the schema in its own way (like being able to use its own index names, etc).



回答8:

I'm not an expert with Doctrine - just started using it myself and I have to admit it is a bit of a mixed experience. It does a lot for you, but it's not always immediately obvious how to tell it to do this or that.

For example when trying to use YAML files with the automatic relationship discovery the many-to-many relationship did not translate correctly into the php model definition. No errors as you mention, because it just did not treat it as many-to-many at all.

I would say that you probably need time to get your head around this or that way of doing things and how the elements interact together. And having the time to do things one step at a time would be a good thing and deal with the issues one at a time in a sort of isolation. Trying to do too much at once can be overwhelming and might make it harder to actually find the place something is going wrong.



回答9:

After some research into the various ORM libraries for PHP, I decided on PHP ActiveRecord. My decision came down to the little-to-no configuration, light-weight nature of the library, and the lack of code generation. Doctrine is simply too powerful for what I need; what PHP ActiveRecord doesn't do I can implement in my wrapper layer. I would suggest taking a moment and examining what your requirements are in an ORM and see if either a simple one like PHP ActiveRecord offers what you need or if a home-rolled active record implementation would be better.



回答10:

A little late for the party, but let me throw my two cents here. I will make connections with Laravel, because that is the framework I use.

Active Record vs. Data Mapping vs. Proper OOP

Laravel and many other frameworks love Active Record. It might be great for simple applications, and it saves you time for trivial DB management. However, from the OOP perspective it is a pure anti-pattern. SoC just got killed. It creates a coupling between the model attributes and SQL column names. Terrible for extensions and future updates.

As your project growths (and yes, it will!), ActiveRecord will be more and more of pain. Don't even think of updating SQL structure easily. Remember, you have the column names all over your PHP code.

I was hired for a project that aims to be quite big down the road. I saw the limits of ActiveRecord. I sat back for 3 weeks and rewrote everything using a Data Mapper, which separates DB from the layers above.

Now, back to the Data Mapper and why I didn't choose Doctrine.

The main idea of Data Mapper is, that it separates your database from your code. And that is the correct approach from the OOP perspective. SoC rules! I reviewed Doctrine in detail, and I immediately didn't like several aspects.

  • The mapping. Why in a world would anyone use comments as commands? I consider this to be an extremely bad practise. Why not just use a PHP Class to store the mapping relations?
  • Yaml or XML for the map. Again, Why?? Why wasting time parsing text files, when a regular PHP Class can be used. Plus, a class can be extended, inhereted, can contain methods, not just data. Etc.
  • If we have a mapper and a model carrying data, then it should be the mapper storing the model. Methods such as $product->save() ar just not good. Model handles data, it should not care about storing anything to the DB. It is a very tight coupling. If we spend time building a mapper, then why not having $mapper->save($product). By definition, it shall be the mapper knowing how to save the data.

Tools such as Doctrine or Eloquent save time at the beginning, no doubt about it. But here is the tricky question for everyone individually. What is the right compromise between /development time/future updates/price/simplicity/following OOP principles/? In the end, it is up to you to answer and decide properly.

My own DataMapper instead of Doctrine

I ended up developing my own DataMapper and I have already used it for several of my small projects. It works very nicely, easy to extend and reuse. Most of the time we just set up parameters and no new code is required.

Here are the key principles:

  • Model carries data, similar to Laravel's model. Example variable $model for the following examples.
  • ModelMap contains a field that maps the attributes of the Model to the columns of the table in the SQL database. ModelMaps knows the table name, id, etc. It knows which attributes should be tranfromed to json, which attributes should be hidden (e.g. deleted_at). This ModelMap contains aliases for columns with the same name (connected tables). Example variable: $modelMap.
  • ModelDataMapper is a class that accepts Model and ModelMap in the controller and provides the store/getById/deleteById functionalities. You simply call $modelMapper->store($model) and that's all.
  • The base DataMapper also handles pagination, search ability, converting arrays to json, it adds time stamps, it checks for soft deletes, etc. For simple usages, the base DataMapper is enough. For anything more complex, it is easy to extend it using inheritance.


回答11:

Using Doctrine ORM in 2016 with Approx experience ~2 - 2.5 years.

Inherent Inconsistency

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

Assume entities are Item and Product. They are connected via Item.product_id to Product.id, and Product contains Product.model that we want to display along with Item.

Here is retrieval of same "product.model" from database, using the above SQL but varying SQL parameters:

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

Point I am making is this:

Output ResultSet structure can change drastically depending on how you write your DQL/ORM SELECT statement.

From array of objects to array of associative array of objects, to array of associative array, depending on how you want to SELECT. Imagine you have to make a change to your SQL, then imagine having to go back to your code and re-do all the code associated with reading data from the result set. Ouch! Ouch! Ouch! Even if it's a few lines of code, you depend on the structure of result set, there is no full decoupling/common standard.

What Doctrine is good at

In some ways it removes dealing with SQL, crafting and maintaining your own tables. It's not perfect. Sometimes it fails and you have to go to MySQL command line and type SQL to adjust things to the point where Doctrine and you are happy, to where Doctrine sees column types as valid and to where you are happy with column types. You don't have to define your own foreign keys or indices, it is done for you auto-magically.

What Doctrine is bad at

Whenever you need to translate any significantly advanced SQL to DQL/ORM, you may struggle. Separately from that, you may also deal with inconsistencies like one above.

Final thoughts

I love Doctrine for creating/modifying tables for me and for converting table data to Objects, and persisting them back, and for using prepared statements and other checks and balances, making my data safer.

I love the feeling of persistent storage being taken care of by Doctrine from within the object oriented interface of PHP. I get that tingly feeling that I can think of my data as being part of my code, and ORM takes care of the dirty stuff of interacting with the database. Database feels more like a local variable and I have gained an appreciation that if you take care of your data, it will love you back.

I hate Doctrine for its inconsistencies and tough learning curve, and having to look up proprietary syntax for DQL when I know how to write stuff in SQL. SQL knowledge is readily available, DQL does not have that many experts out in the wild, nor an accumulated body of knowledge (compared to SQL) to help you when you get stuck.



回答12:

For now I'm using Symfony framework with Doctrine ORM, how about using Doctrine together with plain queries? For e.g. from knpuniversity, I can create custom repository method like:

     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
    }

I'm just use Doctrine Entities for e.g. creating an processing forms, When I need more complex query I just make plain statement and take values I need, from this example I can also pass Entity as variable and take it values for making query. I think this solution is easy understand and it takes less time for building forms, passing data for them and writing complex queries is not as hard as writing them with Doctrine.