问题
I have an entity
class Foo {
public String bar;
}
I want to rename "bar" to "somethingElse". And was planning on using Objectify's @AlsoLoad annotation to achieve that (I am already using Objectify for persistence). So something like:
class Foo {
@AlsoLoad("bar")
public String somethingElse;
}
But any queries of the form:
final Query<Foo> query = OfyService.ofy().load().type(Foo.class)
.filter("somethingElse", "someValue");
Only retrieve entities that have been saved since the rename. Any older entities are ignored.
What is best practice for renaming entity fields so that I can have a single query that will return all records?
回答1:
Note: I'm not an objectify user, the answer is generic, so you'd have to adapt it to objectify specifics.
In general you want to avoid using both bar
and somethingElse
for extended periods of time, primarily because finding matching entities translates into an OR
type of query - .filter("bar", "someValue")
OR .filter("somethingElse", "someValue")
, which is fundamentally unsupported by the datastore. From Restrictions on queries:
The
NOT
,OR
, and!=
operators are not natively supported, but some client libraries may add support on top of Cloud Datastore.
This means that, at best, you'd have to jump through hoops to make something like this work, see, for example, Google Datastore combine (union) multiple sets of entity results to achieve OR condition
My suggestion is to perform a one-off migration and be done with it. It would contain the following steps:
- most likely you'll have to have both properties configured/alive during the migration, so don't just rename
bar
, instead addsomethingElse
and don't immediately deletebar
- in all places where you update the
bar
property also updatesomethingElse
accordingly - add logic to query for all entities which have
bar
but don't havesomethingElse
and re-write them so they also havesomethingElse
. After this step completes all the entities should have asomethingElse
mirroringbar
- in all non-query places where you read
bar
's value switch to readingsomethingElse
instead - check that all indexes containing
somethingElse
are serving, then switch your queries frombar
tosomethingElse
. With this the actual migration is complete and you can execute the cleanup steps below - drop writing the
bar
property - perform queries for all entitites having a
bar
property and re-write them withoutbar
. Note that this could be more expensive than actually leaving these entities alone - drop
bar
from your models and indexes (if applicable to your client library), but only if you deleted the property from all your entities in the previous step
A migration following this approach can be performed slowly as it doesn't require complete service shutdown, it can be done live.
来源:https://stackoverflow.com/questions/47615846/how-to-rename-a-datastore-entity-field-but-be-able-to-retrieve-records-via-old-a