Thank you opengeek for showing me the way. After much ponderance and a little experiment I now understand what's going on and what you are talking about WRT whether it's loaded or not. For the benefit of others, I'll post what I think is correct information.
The following will properly update the item's location_id:
$obj = $modx->getObject('Item', $id);
$obj->set('location_id', $new_location_id);
$obj->save();
As will the following:
$obj->getObjectGraph('Item', '{"Location": {}}', $id);
$obj->addOne($modx->getObject('Location', $new_location_id));
$obj->save();
The reason I was seeing updates not being saved was that I was incorrectly mixing these two techniques:
// Broken Example
$obj->getObjectGraph('Item', '{"Location": {}}', $id);
$obj->set('location_id', $new_location_id);
$obj->save();
Does not work, since the save sees the related object (the Location) which hasn't changed.
Thanks again, I've got it now!