How to read-modify-write a multivalue entity-reference field I have some D8 entity code that does read-modify-write on a multivalue entity-reference field. The modification required is to change references to one entity to refer to another, without changing other references.

I get an exception thrown in $entity-&gt;set(...) saying that the Value is not an entity. I presume I'm calling the wrong thin somewhere but I don't see what the correct call pattern would be.

What I have at present is, and here $field_values is a EntityReferenceFieldItemList:

  $field = '...';
  $entity = $storage-&gt;load(...);

  $field_values = $entity-&gt;{$field};
  foreach ($field_values as $k =&gt; &amp;$item) {
    $target_id = $item-&gt;get('target_id')-&gt;getValue();
    if ($target_id === $old_value-&gt;id()) {
      $changed = TRUE;
      $item-&gt;set('target_id', $new_value);
    }
  }
  if ($changed) {
    var_dump($field_values);
    $entity-&gt;set($field, $field_values);
    $entity-&gt;save();
  }


where $old_value and $new_value are both EntityInterface objects and $field_values is an EntityReferenceFieldItemList.
foreach (entity-&gt;get($field) as $k =&gt; $item) {
    $target_id = $item-&gt;target_id;
    if ($target_id == $old_value-&gt;id()) {
      $changed = TRUE;
      $item-&gt;target_id = $new_value;
    }
  }

  if ($changed) {
    $entity-&gt;save();
  }


That's it. You don't need to set any values, they are objects, your loop already updates them. You also don't need to loop over it by reference.

I just simplified it a bit because you can access target_id as a property through __set() and __get(), which has the advantage that you directly get the value and don't need to call getValue() on it.

See https://wizzlern.nl/drupal/drupal-8-entity-cheat-sheet for more information for example.