I generally don't understand the example. An "Invoice" object should capture everything relevant to the purchase, including prices, taxes, shipping, etc. Identifying a "Product" via ID is fine, and that Product may even have a "current price" attached to it. But in no way should that referenced Product object impact the captured Invoice object.
I don't understand. That's exactly what domain modeling is. Putting names to the data you need to store and, in this case, capture at a particular moment in time.
Let's put it this way. Do you think it is reasonable to store the taxes as a reference, or the shipping cost? We would never consider it appropriate to say, "Go look up the shipping cost for a 5lb package from here to here." Oh, and by the way, this is using a live reference to a customer object, for which the shipping address might very well have changed.
Of course we would not do this. So why would it appropriate for a product price? An invoice is the capture of all this information at the moment the purchase is made. That is its purpose. If we did not need this moment-in-time capture, then the concept of an invoice would not even exist.
Coming up with names for groups of data that we want to consider as atomic is what object orientation does, it seems to me.
I also think that that is its Achilles heel - by giving names to groups, only those privy to the internal representation of the atom can combine their functionality with its data. So you need to either merge your functionality with the atom's data (aka define an instance method) thereby coupling "things" with "actions", or you need to leak the atom's internals to outsiders (aka write a method somewhere else that "knows too much" about the atom's internal representation).