Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Datastore lazy reference save/update behavior #1205

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

zhumin8
Copy link
Contributor

@zhumin8 zhumin8 commented Jul 29, 2022

The issue:

  • when the lazy referenced child is not evaluated, save to datastore works as intended by only saving its key and not loading it.
  • When this lazy referenced child is loaded/updated, the code logic treats it as a regular entity, where in fact, its value can only be accessed via proxy. As result, it tries to allocate a new key, hence error observed in Saving a child referenced via @LazyReference DatastoreDataException #1203. Or if the id field is Long, it would not fail, but rather saved to Datastore as a new entity with null values.

Trying to fix by loading the real entity when attempting to save. When the entity is not loaded/evaluated, it will still fall to original logic without loading it.
fixes #1203

SonarCloud failed on test coverage, I'll look into adding tests.

Copy link
Contributor

@elefeint elefeint left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always worry about making lazy loading more complicated -- it could make saving much slower because now you have to go and read each entity before saving.

I have two general questions related to this:

  1. In the original reproduction scenario, I get that saving the child individually fails. But what happens if you invoke save on the parent entity instead? Does the child gets updated properly?
  2. If the child entity did not get updated, will this logic still trigger? I'd like to avoid triggering each child retrieval unless it's absolutely necessary.

@@ -523,7 +527,7 @@ private static StructuredQuery.OrderBy createOrderBy(

private List<Entity> convertToEntityForSave(
Object entity, Set<Key> persistedEntities, Key... ancestors) {
if (ancestors != null) {
if (ancestors.length != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it still be null? Maybe ancestors != null && ancestors.length != 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I thought that since varargs are treated as arrays, checking length should be enough. In our case, when there is no ancestors, no argument of type Key is passed down, and ancestors would be an empty array.
But since you point this out, I found if only a null is passed in, then ancestors == null. So I'll add both checks just to be cautious.

Comment on lines 37 to 40
// public void setId(String id) {
// this.id = id;
// }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove if not needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, missed this one.

@sonarcloud
Copy link

sonarcloud bot commented Aug 10, 2022

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 2 Code Smells

33.3% 33.3% Coverage
0.0% 0.0% Duplication

Copy link
Contributor

@elefeint elefeint left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just do something about the test coverage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Saving a child referenced via @LazyReference DatastoreDataException
2 participants