Why ORM is broken?

I believe there are 4major areas in which all of ORM implementations have significant problems:

ORMs suck at aggregating or building report data. Many projects that have to follow a very strict dependance on ORM would still use stored procedures or raw queries to extract aggregated report data. DQL is also — only a partial solution to this problem. ORM level the ground for the databases. If your database has a unique feature such as ability to perform full-text or geo search, join tables or use built-in expression language — ORM does not offer ways to use those features. There are work-arounds such as “query” builders that integrate into ORM, but they disregard isolation of persistence logic. They are also not part of ORM itself and cannot be fed back into ORM. Performance of ORMs is quite poor and not because of technical implementation, but rather due to logical design. Problems such as (n+1) and huge arrays with “id”s are waiting to blow under the hood of your application and require you to tinker around to find and fix them. Similarly ORM does NOT help to reduce number of queries and amount of data sent or retrieved form the database. Top-level integration of ORM is quite bad. I haven’t seen a piece of PHP code that would work well with arbitrary ORM model / entity. For example, Sign-up form implementation in Web Apps may have to spell out all the fields and even work hard on providing data for those drop-downs / auto-complete callbacks.

The problems that I have listed cannot simply be “fixed”. Author of a pattern has a choice to select what concerns will be abstracted from the developer and where developer must pay close attention.

By design ORM tries to abstract “database” operations with a code like this:

function getBasketTotal(User $user) {

$basket = $user->getBasket();

$total = 0;

foreach ($basket->getItems() as $item) {

$total += $item->cost;

}

return $total;

};

This code would work fine with a zero-latency database, but in reality queries take time and fetching and processing unnecessary data take toll on CPU and Memory of your application.

For comparison Agile Data defines pattern differently, enabling code like this:

function getBasketTotal(User $user) {

return $user

->ref('basket')

->ref('Items')

->action('sum', 'cost')

->getOne();

}

Capable databases will implement ‘sum’ aggregation over a specified field while making sure not to drop you out of Domain Model logic.

A special mention to Query-builders:

$user->getBasket()->sum('cost');

Although his code looks similar, it’s defined through a “Query Builder” which, for example, implies that ‘cost’ is a physical field inside a table. Agile Data does not require developer to know specifics of ‘cost’ field, which can be defined through “join” or “expression”.