I'm am trying to update a node field programatically in d8 without saving the entire node.

Here's a sample of code:

function test_updattte($nid){

    $entity =  \Drupal\node\Entity\Node::load($nid);


    $body_field = $entity->get('body');
    $field_value = $body_field->getValue();
     $field_value[0]['value'] = 'aafdfd';
  
    $field_value[0]['summary'] = $field_value[0]['value'];
    $body_field->setValue($field_value, TRUE);

}

But the field value is not updated unless i save the entire entity.

In d7 there was the field_attach_update function.

Anyone can help ?

Comments

nitin.k’s picture

This does not seem to be existing in D8 till now for updating you need to save the node !!

HannahMR’s picture

I've got the same problem as well. Did you find a solution?

dkre’s picture

$entity->save();

j.b’s picture

Doesn't entity->save(), save all fields of the the entity ?

What we want is to update/insert a specific field only without changing the changed timestamp of the entity.

j.b’s picture

@HannahMR

I did not find a solution up to now and you ?

i've come across this page
http://www.drupalcontrib.org/api/drupal/drupal!core!modules!field!field....

Its says
Saves field data for an existing entity.

@deprecated as of Drupal 8.0. Use the entity system instead.

How do we use the entity system to achieve the same function as field_attach_update

j.b’s picture

The solution i've come up with is to do
First a delete on the concerned field to be inserted/updated respective table
then an insert

dkre’s picture

removed

randomyao22’s picture

Same problem here.
I need to update a filed value (which need to contain a entity id) after a new entity created. I can do it in hook_entity_insert() but I cannot save the entity again inside that hook. It will give me a error.
D7 has a solution by field_attach_update function, but that function has been removed in D8.

dkre’s picture

I believe that's because you don't do $entity->save() within the hook, you just alter the field value within the hook.

randomyao22’s picture

Thanks dkre. But $entity->save() inside that hook_entity_insert will cause a error like this:

Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '14' for key 'PRIMARY': INSERT INTO {node_revision} (nid, vid, langcode, revision_timestamp, revision_uid, revision_log) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 14 [:db_insert_placeholder_1] => 14 [:db_insert_placeholder_2] => en [:db_insert_placeholder_3] => 1491441432 [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => ) in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 770 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

I think you can't use that $entity->save() within another $entity->save()... How do you think?

randomyao22’s picture

I think I fixed the error by set revision to false.

<?php
/**
 * Implements hook_entity_insert().
 */
function my_module_entity_insert(EntityInterface $entity) {
  if ($entity instanceof \Drupal\node\NodeInterface && $entity->bundle() == 'my_content_type') {
    $id = $entity->id();
    $my_number = 'custom_format' . $id;
    $entity->set('field_my_number', $my_number);
    // Set revision to false will prevent it get errors.
    $entity->setNewRevision(FALSE);
    $entity->save();
  }
}
?>
helonaut’s picture

Hello,

I hope I can add this to this question, otherwise I will create a new topic...
When doing exactly like OP does, but than setting the "changed" field like so: $node->changed = "1500892843";
But where the timestamp is variable per node (which are set correctly every time, because I checked the reported values every time).
Half of the time, the nodes get updated correctly (getting the timestamp values) and half of the time they just get the current_time value.
Can somebody please explain me why this is happening and how I can prevent this behavior?

EDIT: in the meanwhile, I stumbled upon this information on an external website. It describes this problem and says the presave function is the only way possible to (reliably) set the $node->changed value. In that same source, they question the inconsequent behavior between $node->created and $node->changed, which I think is a valid remark. So my question still stands... Why is this 50/50 correct instead of giving the same result (setting correct value all the time OR setting the false value all the time) with each update?

1kenthomas’s picture

That's referring to D7,  right?  we're trying to make D8 do this?

helonaut’s picture

No I'm using D8?

woodseowl’s picture

I came upon this because I wanted to have the "changed" value not get changed, as mentioned. If I set $node->setChangedTime() to the original value, it would get ignored. Not sure where in the core code it is looking for those field diffs or even grabbing the changed time. But then if I set the changed time to something other than the original value, it worked. So, my code ended up like this:

$changed = $node->getChangedTime();
$node->setNewRevision(FALSE);
$node->save();
// Set it back to the original changed time.
$node->setChangedTime($changed);
$node->save();

Not sure if a $node->setNewRevision(FALSE) needs to be there again before the second save.

rajesh.vishwakarma’s picture

I can't use save() method due to the below reason 

  1. save() method change the timestamp.
  2. I don't run any hooks to be executed with this save.

Can someone help here? Looking for alternative solution for field_attach_update

jaypan’s picture

Well, you're trying to bypass all the APIs. It's rare someone will be able to support you on how to work around Drupal's APIs, people here explain how to work with the APIs. Generally, when you are trying put together a solution that bypasses Drupal, you'll need to do the work yourself, as others will not likely have done the same thing.

Contact me to contract me for D7 -> D10/11 migrations.

rajesh.vishwakarma’s picture

I want an alternative option for field_attach_update. I think this also bypasses all APIs.

imclean’s picture

This is not a good idea. That said, if you're that keen then just write directly to the database. Why bother with using any of the APIs?