There are two concerns to deal with - which are orthogonal to each other:
1) The lower end of persistence
This is where you have to deal with Connections,Queries, Resultsets and the like. Typically you use the one or the other framework which gives you a facade-pattern at hand, which abstracts away the dirty stuff away so that you only tell, what you want to know(Resultset from Query) and where the framework could find it (Query and Connection). What you do with the resultset is up to you.
When your paradigm is OOP, there is an additional step involved: assembling the resultset to objects. Either you do it manually or have an object-relational-mapper doing the job for you.
2) The abstraction within your application
On top of this low level layer sits the abstraction with which your application deals. There is the DataAccessObject (DAO)-Layer or the Repository-Layer. Both generate Objects for your Application to work with.
Which one you are using has no effect on the answer of your question.
Your question is on the one hand on modeling (»How to handle relationships between objects« Answer: via Composition/Aggregation) and on how to fill the object (and its dependencies) with data.
Is it done using Dependency Injection and if so, where is the dependency created?
This is the way to go. There are two ways:
1) You make the DI explicit and define a constructor. When creating the Object, you are able to create all dependencies first and inject them via constructor or setter injection
2) You use a framework, which does the magic for you. Oftentimes reflection is involved, i.e. there are possibilities within some languages to examine and manipulate objects on the fly. The injection is done transparently for the user by the framework.
This is independend from the DAO/Repository-pattern.
I am not using an ORM tool and don't want to as I like to explore these basic patterns directly
That's a noble approach, but not in every case productive. Most of the time, you want to get stuff done. For educational purposes, you could go down that road. But I would not recommend it.
Look out for a flexible ORM-Framework, which gives you a helping hand when needed without forcing you in one way or the other. Not in every case is the ootB generated query effective. A good framework let's you use SQL when needed and takes only care of the assembling part.
Best Answer
According to me, passing a persistable POJO, like for instance a bean managed by JPA, is not THE good practice.
Why?
I see three main reasons:
I prefer letting my service layer convert entities to corresponding DTO in both directions. DAO still returning entity (it's not its job to ensure the conversion).