In a typical program running in memory, objects will almost always be stored by reference as pointers, so you ARE storing IDs for B and C, it's just that you don't deal with the details yourself, the language hides them from you.
Loading and storing the "Entire Object" is a questionable concept. I know you are trying to be language independent, but one of the first things that really helped me "Get" OO is that nearly every object should have a lifecycle of its own.
If you have object A that "Contains" object B, and you pass a reference to object B to object C, then Object A has to know something about object C, this is completely NOT OK. Freeing up object B's lifecycle so that object A knows nothing of object C is one of the core concepts that makes OO work.
So if that's what you meant by storing the entire object, then no--never do that.
And that's true of Databases and other storage as well. Even if one object is responsible for destroying another, it should rarely contain the other objects' data.
And (although I think you meant to say "pull Objects B and C", not "methods"), the concept of being able to pass an object from another is also very useful and there is generally nothing wrong with it with one caveat:
Remember that an object has no control over what goes on outside itself. It could be passed around, methods called in a semi-random order, etc. Therefore it's helpful to keep your object as safe as possible. If something is called in the wrong order, or an invalid variable is passed in, or you find that somehow you've entered an invalid state, Fail early and Fail LOUD so that the programmer who made a mistake called it.
You also want to make it as difficult as possible to get into an illegal state--this means keep your object small and simple, make variables final whenever possible and try not to have too many places where parameter call order matters.