> And if you need real SQL intervals, Django pushes you towards raw expressions or `Func()` wrappers.
It's possible to use a very similar construct to SQL Alchemy here by using the `Now` [function](https://docs.djangoproject.com/en/6.0/ref/models/database-fu...) (it uses `STATEMENT_TIMESTAMP` which is likely more correct than `NOW()` here alternatively there is `TransactionNow`) by doing `Now() - timedelta(days=30)`.
Parameterized queries have been a thing for decades, which mitigate SQL injection attacks.[1] This is true of the examples in the post too, they used this:
query = """
SELECT * from tasks
WHERE id = $1
AND state = $2
FOR UPDATE SKIP LOCKED
"""
rec = await self.db.fetchone(query=query, args=[task_id, TaskState.PENDING], connection=connection)
Porsager’s Postgres package does a great job of letting you feel like you’re writing raw sql, but avoids the attack vectors.
Anyway, I agree that ORMs are pretty terrible. I like writing SQL or using a lightweight builder like Kysely. Was a huge Dapper fan back in my C# days.
There are plenty of reasonable alternatives to ORMs that don’t open you to SQL injection attacks.
Though the article mentions the distinction between ORMs and query builders, it doesn't really make a case against query builders being bad. After all, it wraps up by building a kinda crappy one-off query builder.
While there is a compelling case for leveraging the full power of Postgres (especially features like SKIP LOCKED and pg_notify), this approach feels like a classic trade-off between fine-grained control and long-term maintainability.
Relying solely on raw SQL and manual mapping certainly eliminates "ORM magic," but it replaces it with a significant maintenance burden.
For specialized, high-performance systems like video transcoding, this level of hand-tuning is a superpower; however, for the average CRUD-heavy SaaS app, the "boilerplate tax" of writing eighty lines of repository code for a simple related insert might eventually cost more in development velocity than the performance gains are worth.
> for the average CRUD-heavy SaaS app, the "boilerplate tax" of writing eighty lines of repository code for a simple related insert might eventually cost more in development velocity than the performance gains are worth.
Perhaps, but IME this kind of thing is much more often the cause of poor performance in CRUD apps than the frontend frameworks that are usually blamed. I have been able to make very snappy SaaS apps by minimizing the number of queries that my API endpoints need to perform.
I've also found that the ORM mainly reduces boilerplate for Insert/Update operations, but often adds a very significant amount of boilerplate for read queries. We ended up using a very lightweight orms for simple inserts / upserts and writing raw SQL for anything else.
No, just because raw SQL queries work great for your toy blog/todo app with 3 tables and simple relationships, doesn't mean they work great for real world business applications with 100 tables and complex networks of relationships. Try maintaining the latter before you make blanket claims like "ORM bad".
> just because raw SQL queries work great for your toy blog/todo app with 3 tables
In my experience, ORMs work well for toy projects, but become cumbersome to maintain in enterprise ones, especially where performance matters. There is a large overlap between engineers who refuse to learn SQL because it's not "convenient", and those who prefer ORMs because they are "easier", resulting in cohorts that don't know how to use either.
But also, I don't see how ORMs make managing large databases any easier, other than those with embedded migration capabilities, which can be very well extracted to their own tools.
When someone says that X is bad and not to use it, what I really hear is, “I’m ignorant to some use cases but that won’t stop me from having a loud opinion.”
I oscillate on being tired or amused by just how common tech people make this basic error. But I don’t believe it’s ever in bad faith. I think people in general suffer from perceiving their context as the context even though they’ve experienced maybe 1% of what there is out there.
Mostly agreed with the author about ORMs. The provided querying abstraction works against developers when queries reach a certain level of complexity, and at the end of the day, understanding these complexities is not optional.
But I would caution against adding too much business logic to the database, and tying message passing to your database doesn’t sound like the best of ideas.
But there's also value gained in it, isn't there? I very much like doctrine's query builders and being able to analyze and manipulate queries programmatically, e.g. dynamically add a filter to a query and a join if needed. That's pretty simple with a query builder once you've gotten comfortable with the concept and the ORM itself, but it's pretty hard to do with plain sql unless you write plenty of specific code to handle all the known things you might care about.
Considering anybody with a noggin is going to be separating the SQL into it’s own module or whatever rather than just throwing straight inline SQL at your database wherever you it, you’re hardly less likely to have things like accidental writes, anyway. This is clearly someone who fell in love with Postgres, felt ORM abstractions that diluted the Postgres goodness were bad, and then did some mental experiments to consider all of the theoretical ways ORMs suck.
Absolutely, “ORM == bad” viewpoint strikes me as highly ignorant of all the benefits they provide, particularly in statically typed languages.
People like me don’t choose an ORM to save me from having to learn SQL (which you’ll still need to know), it’s because 99% of the time it’s a no brainer as it vastly increases productivity and reduces bugs.
In a language like C#, EF Core can easily cover 95% (likely more) of your SQL needs with performance as good as raw SQL, for the small percentage of use cases its performance is lacking, you fall back to raw SQL.
But if saving you from writing 95%+ of SQL queries was not compelling enough, it’s just one benefit of EF Core. Another major time saving benefit is not having to manually map a SQL result to objects.
But an often super underrated and incredibly valuable benefit, especially on substantial sized code bases, is the type safety aspect. The queries written using LINQ are checked for free at compile time against mistakes in column or table names.
Want to refactor your schema because your business domain has shifted or you just understand it better than before? No problem. Use standard refactoring tools on your C# code base, have EF Core generate the migration and you’re done in 10s of minutes, including fixing all your “SQL queries” (which were in LINQ).
EF Core is almost always a no brainer for any team who wants high quality and velocity.
Totally. ORMs are not evil. They help to reduce the boilerplate and improve the code maintainability.
We have a complex project with a custom back-end framework that also includes a custom ORM. The ORM covers about 95% of the use cases just fine. It reduces a lot of boilerplate and also makes it possible to find the logic much easier (for example, setting and reading some column from a specific table). Although I have to say, it works that well also thanks to good integration with the framework (fronted, included) and advanced features, like calculated fields with automatic recalculation triggering, integration with user permissions, ability to define custom user permission validation logic before / after saving rows, etc. If we really need an unusual operation where the ORM doesn't suffice (most of the time complicated search queries or some aggregation), we can write raw SQL and, if possible, encapsulate it at repository / service level. But 95% of use cases are covered by the ORM (including the management of parent / child relationships).
I think some "old school" folks like to bash ORMs and view them as very limited and inefficient compared to raw SQL. But you can use them both: primarily ORM and in specific cases switching to raw SQL when ORM doesn't suffice.
Agreed, ORMs are OK to start with if you like and then optimize the queries where needed.
There are cases where older ORMS might be more optimized for some cases compared to new ones, and vice versa.
Avoiding learning SQL is the biggest gap. Selecting a NoSQL database because it seems easier, and then spending so much time trying to make a NoSQL database into a relational database is usually not too pretty.
It’s been swinging for at least 30 years, Toplink came out in 1994, and I have worked on systems that were written half a decade earlier that contained things we’d all call ORMs.
But it’s a bot writing the above. Look at the user's comment history. "Not x, but y", poorly formatted listicles, mid-paragraph questions to the reader, and em dashes galore.
Gavin King, creator of hibernate has said many times that you don’t have to use it for everything. Indeed your code can use the entity manager to execute sql. The problem is sql databases are hard, data modeling is hard, it requires a lot of care discipline and even experience (gasp!) to get right.
I’m glad you’re head-over-heels in love with Postgres— it’s really cool, and I’ve occasionally had projects that really benefited from it… but most of those incredible features just aren’t useful for run-of-the-mill projects. Learning how to profile your ORM queries is a lot easier than maintaining a bunch of code from a different language embedded into your code base. If you’re writing articles about Postgres, you probably have no idea how much of a PITA that context switch is in practice. It’s funny how getting expertise in something can make it more difficult to understand why it’s useful to other people, and how they use it.
There are projects, like SQLC, that cover most of the perceived advantages of ORMs, without the downsides.
One of these downsides is, in my opinion, the fact that they hide the very details of the implementation one necessarily needs to understand, in order to debug it.
Doctor_Fegg|7 days ago
dakolli|7 days ago
janmarsal|7 days ago
manuelabeledo|7 days ago
charettes|7 days ago
>“Roughly” because Django ORM doesn’t support the JSONB `?` operator.
The `has_key` [lookup](https://docs.djangoproject.com/en/6.0/topics/db/queries/#has...) does exactly that.
> And if you need real SQL intervals, Django pushes you towards raw expressions or `Func()` wrappers.
It's possible to use a very similar construct to SQL Alchemy here by using the `Now` [function](https://docs.djangoproject.com/en/6.0/ref/models/database-fu...) (it uses `STATEMENT_TIMESTAMP` which is likely more correct than `NOW()` here alternatively there is `TransactionNow`) by doing `Now() - timedelta(days=30)`.
The result is the following `filter` call
which translates to the following SQL which can be confirmed in [this playground](https://dryorm.xterm.info/hn-47110310)aragilar|6 days ago
sunbum|7 days ago
- Your friendly local pentester
[1] - https://en.wikipedia.org/wiki/SQL_injection
lowsong|7 days ago
christophilus|7 days ago
Anyway, I agree that ORMs are pretty terrible. I like writing SQL or using a lightweight builder like Kysely. Was a huge Dapper fan back in my C# days.
There are plenty of reasonable alternatives to ORMs that don’t open you to SQL injection attacks.
Zanfa|7 days ago
altmanaltman|7 days ago
Relying solely on raw SQL and manual mapping certainly eliminates "ORM magic," but it replaces it with a significant maintenance burden.
For specialized, high-performance systems like video transcoding, this level of hand-tuning is a superpower; however, for the average CRUD-heavy SaaS app, the "boilerplate tax" of writing eighty lines of repository code for a simple related insert might eventually cost more in development velocity than the performance gains are worth.
nicoburns|7 days ago
Perhaps, but IME this kind of thing is much more often the cause of poor performance in CRUD apps than the frontend frameworks that are usually blamed. I have been able to make very snappy SaaS apps by minimizing the number of queries that my API endpoints need to perform.
I've also found that the ORM mainly reduces boilerplate for Insert/Update operations, but often adds a very significant amount of boilerplate for read queries. We ended up using a very lightweight orms for simple inserts / upserts and writing raw SQL for anything else.
manuelabeledo|7 days ago
Where does SQL fall in the video transcoding pipeline?
unknown|7 days ago
[deleted]
unknown|7 days ago
[deleted]
RockRobotRock|7 days ago
rrr_oh_man|7 days ago
bakugo|7 days ago
No, just because raw SQL queries work great for your toy blog/todo app with 3 tables and simple relationships, doesn't mean they work great for real world business applications with 100 tables and complex networks of relationships. Try maintaining the latter before you make blanket claims like "ORM bad".
manuelabeledo|7 days ago
In my experience, ORMs work well for toy projects, but become cumbersome to maintain in enterprise ones, especially where performance matters. There is a large overlap between engineers who refuse to learn SQL because it's not "convenient", and those who prefer ORMs because they are "easier", resulting in cohorts that don't know how to use either.
But also, I don't see how ORMs make managing large databases any easier, other than those with embedded migration capabilities, which can be very well extracted to their own tools.
nubinetwork|7 days ago
fud101|6 days ago
Waterluvian|7 days ago
I oscillate on being tired or amused by just how common tech people make this basic error. But I don’t believe it’s ever in bad faith. I think people in general suffer from perceiving their context as the context even though they’ve experienced maybe 1% of what there is out there.
manuelabeledo|7 days ago
But I would caution against adding too much business logic to the database, and tying message passing to your database doesn’t sound like the best of ideas.
luckylion|7 days ago
tags2k|7 days ago
DrewADesign|7 days ago
ecshafer|7 days ago
MarcLore|7 days ago
[deleted]
jonathanlydall|7 days ago
People like me don’t choose an ORM to save me from having to learn SQL (which you’ll still need to know), it’s because 99% of the time it’s a no brainer as it vastly increases productivity and reduces bugs.
In a language like C#, EF Core can easily cover 95% (likely more) of your SQL needs with performance as good as raw SQL, for the small percentage of use cases its performance is lacking, you fall back to raw SQL.
But if saving you from writing 95%+ of SQL queries was not compelling enough, it’s just one benefit of EF Core. Another major time saving benefit is not having to manually map a SQL result to objects.
But an often super underrated and incredibly valuable benefit, especially on substantial sized code bases, is the type safety aspect. The queries written using LINQ are checked for free at compile time against mistakes in column or table names.
Want to refactor your schema because your business domain has shifted or you just understand it better than before? No problem. Use standard refactoring tools on your C# code base, have EF Core generate the migration and you’re done in 10s of minutes, including fixing all your “SQL queries” (which were in LINQ).
EF Core is almost always a no brainer for any team who wants high quality and velocity.
senfiaj|7 days ago
We have a complex project with a custom back-end framework that also includes a custom ORM. The ORM covers about 95% of the use cases just fine. It reduces a lot of boilerplate and also makes it possible to find the logic much easier (for example, setting and reading some column from a specific table). Although I have to say, it works that well also thanks to good integration with the framework (fronted, included) and advanced features, like calculated fields with automatic recalculation triggering, integration with user permissions, ability to define custom user permission validation logic before / after saving rows, etc. If we really need an unusual operation where the ORM doesn't suffice (most of the time complicated search queries or some aggregation), we can write raw SQL and, if possible, encapsulate it at repository / service level. But 95% of use cases are covered by the ORM (including the management of parent / child relationships).
I think some "old school" folks like to bash ORMs and view them as very limited and inefficient compared to raw SQL. But you can use them both: primarily ORM and in specific cases switching to raw SQL when ORM doesn't suffice.
j45|7 days ago
There are cases where older ORMS might be more optimized for some cases compared to new ones, and vice versa.
Avoiding learning SQL is the biggest gap. Selecting a NoSQL database because it seems easier, and then spending so much time trying to make a NoSQL database into a relational database is usually not too pretty.
aardvark179|7 days ago
rrr_oh_man|7 days ago
But it’s a bot writing the above. Look at the user's comment history. "Not x, but y", poorly formatted listicles, mid-paragraph questions to the reader, and em dashes galore.
le-mark|7 days ago
unknown|7 days ago
[deleted]
throwaway613746|7 days ago
[deleted]
DrewADesign|7 days ago
manuelabeledo|7 days ago
One of these downsides is, in my opinion, the fact that they hide the very details of the implementation one necessarily needs to understand, in order to debug it.