I strongly recommend you research using some kind of data abstraction layer. In Perl I use Data::ObjectDriver and/or Moose. Every language has its equivalent. What these frameworks provide is a simple way for you to define the properties of an object, and then the framework will manage interfacing with the database for you. Often there is no need for you to create your database tables, or even write a single line of SQL code. Not only does this make the mundane task of writing SQL for each of your objects completely unnecessary, but these frameworks also help you solve other potentially large architectural problems, like database partitioning and caching.
Let's just look at Data::ObjectDriver as an example, which I select only because I have experience using it. The source code samples provided by its documentation make the API clear: you define a data structure and a database, and the framework will then create the tables for you make interacting with a recipe for example as simple as:
my $recipe = Recipe->new;
my $ingredient = Ingredient->new;
Now here is one more advantage of using a framework like this: one of the things Data::ObjectDriver does for you automatically is to interface with a memcached server should one be present. This automatically offloads a lot of traffic from your database to a low-latency caching system over the network. This ability and others are capabilities you get "for free." And from the big picture point of view, a developer should never bother themselves with reinventing the wheel -- unless the wheel you need has not yet been invented. :)
Now, let's return to your question.
Am I better off making one big call to the database and populating my objects and working with these objects, or should I retrieve data from the db only when needed?
My answer to this question is therefore, don't worry about it, but only if you are using a good data abstraction layer. A good data abstraction layer will have addressed many scaling problems and challenges already, or least provide specific remedies for common problems you might face.
If you find that you must write this code yourself, then I would err on the side of simplicity. Keep your database queries simple, even if that means requiring more of them for any given request. Then use memcached to cache the results of your query. That way, even if it takes 100 queries to build a single object, then so be it. The first time through, generate the 100 queries. In subsequent requests, you won't hit the database at all.