1

Using Entity API, I can create entities easily like this:

// SomeEntity class extends ContentEntityBase
$entity = SomeEntity::create(['my_id' => 'id123']);
$entity->save();

Works fine as long as my_id is unique. When it's not, I get EntityStorageException with message complaining about my_id not being unique. I could first try to load entity to see if it exists and update it manually but that seems like unnecessary overhead.

Is there a way to automatically save or update existing entity programatically?

2 Answers 2

3

Not really. To figure out if an entity exists, you have to check that somehow.

If you're trying to optimize, you could run an entity query instead of loading it completely. But in case you want to update, you need to load the original entity anyway, so just do that.

$entity = SomeEntity::load(['my_id' => 'id123']);
if (!$entity) {
  $entity = SomeEntity::create(['my_id' => 'id123']);
}
$entity->save();
2
  • This seems like a bad idea. I did more digging and came up with a solution. Commented Dec 28, 2015 at 22:42
  • @SiliconMind Berdir is one of the official maintainers of the Entity subsystem in Drupal 8. I usually listen to what he says :)
    – mpdonadio
    Commented Dec 29, 2015 at 0:06
0

Using SomeEntity::load() first manually and then manually updating fields if entity exists seemed like huge overhead and inefficient. In that case, how Entity::save() knows if it's saving new entity or loaded from database? My investigation led me to EntityStorageBase::create() method which invokes Entity::enforceIsNew(true).

So the answer seems to be simple: make sure that the entity that was created via SomeEntity::create() was explicitly instructed that it should not enforce new when saving. This seems to work fine:

// SomeEntity class extends ContentEntityBase
$entity = SomeEntity::create(['my_id' => 'id123']);
// Call Entity::enforceIsNew(false) only if you know that entity already exists.
$entity->enforceIsNew(false);
$entity->save();

Note that entities might have metadata attached like creation date, author etc. This approach would overwrite and lose that.

5
  • This won't work. enforceIsNew(FALSE) means it will always try to update an existing entity. It will run an UPDATE query against a non-existing ID and not create anything.
    – Berdir
    Commented Dec 29, 2015 at 8:08
  • @Berdir that's why I wrote: Call Entity::enforceIsNew(false) only if you know that entity already exists. I know it's not a perfect solution, but better than loading whole entity and in case it exists, updating it's fields manually. Also in my scenario this logic with enforceIsNew(false) could be coded into SomeEntity::save() override. Commented Dec 29, 2015 at 12:04
  • Well, and how do you know that? Wasn't exactly that your original question? Trying to load it is still the easiest way to do that. And re-creating and force-updating an existing entity might work for you, but entities often have metadata attached like original creation date, author etc. Your approach would overwrite and lose that.
    – Berdir
    Commented Dec 29, 2015 at 12:42
  • @Berdir When I perform updates in bulk, it's better to load only entity IDs in bulk and conditionally call enforceIsNew(false). However, as you noted, meta data is lost and that's not good although I can live with that in my scenario. However it would be great if Entity API was smart enough to update only changed data. Commented Dec 29, 2015 at 13:28
  • It is smart, for configurable fields only at the moment. But to do that, it needs the old values, which it gets by loading the original entity during save, so that happens anyway. However, that wouldn't solve your problem, since your new entity would have a new created timestamp and it would explicitly save that. If you have bulk, you can also do a loadMultiple().
    – Berdir
    Commented Dec 29, 2015 at 13:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.