Problem is that doesn't work nicely in a one-to-many or many-to-many relationship - fetching it in the original query means deduplicating in the application code, or not fetching it and getting related rows afterwards. And that's one of the things ORMs are really good at.
For a video game, simulation, CAD program or other stateful program, loading an object graph can be natural. In that context, an object store, document database, serialized state, or ORM-backed persistence layer may be a reasonable fit. This isn't database design, it's application design.
But in data management applications, the job is to derive specific information from stored facts. For that, SQL is not an implementation detail behind objects; it is the main abstraction. The whole point is to ask for the shape of data your application actually needs, not to arbitrarily hydrate objects and reinvent a bespoke querying engine on the client side. I can barely even remember the number of times that I've ripped an ORM out of a system because the code to interact with hydrated objects had devolved into a single-purpose database engine, a sprawling mess of code, seemingly well organised into objects, but ultimately wasteful.
Often, de-duplicating in code is a perfectly fine solution, and significantly more performant than multiple round-trips. A join that repeats parent columns is not a flaw in SQL. It is only a problem if the application insists on rebuilding a nested object graph instead of asking for the shape of data it actually needs.
If the data returned by the query does not match what you are presenting, the answer should not be to fetch a pile of related objects and interrogate them in memory. It is to use more SQL to further digest the data so that the result set more closely matches what you intend to present to the user.