Only Ancestor queries are allowed inside transactions, how to deal with it?
Asked Answered
M

2

8

I need to do a query inside a Transaction, however I don't know the Entity @Id, what I have is a value of a field, like a username but not the ID,

So in other words, I can't create a Key to do the query. How can I do a query to get an Entity inside a Transaction?

Machiavelli answered 6/7, 2012 at 11:5 Comment(1)
As you know you cannot do that. It seems to be a design problem. May be you can try to ask this question by what you are trying to do.Bobbyebobbysocks
B
15

Without delving into deeper design issues, there are really two options:

1) Run the query outside of a transaction.

Objectify (which you tagged this post with) makes it easy to execute non-transactional queries even while inside a transaction. Just spawn a new ofy instance not associated with a transaction and use that to run the query... then go back to working in your transaction. Keep in mind that this does break out of the transaction and could have effects on the integrity of the operation. Often it doesn't matter.

If you're using Objectify4 you can just run the operation like this:

ofy.transactionless.load().type(Thing.class).filter("field", value)...etc

2) Use a lookup entity

This is typically the right answer when dealing with things like usernames. Create a separate entity which maps the username to your User object like this:

class Username {
    @Id String username;
    Key<User> user;
}

Use XG transactions to create a Username every time you create a User, and update it if you allow your usernames to change. Now, to perform a transactional lookup of User by username, first lookup the Username and then use that to lookup the User.

Bulbul answered 6/7, 2012 at 15:40 Comment(4)
I want to use String Id, I'm ok for it for Username ID's however hwen I have a String ID which is a random string, perhaps that can range from short strings to very long string. I can see the the Datastore Key is "bloating", I mean, the GAE Key is proportional to the length of the @Id, how can I deal with that?Machiavelli
It sounds like premature optimization. I wouldn't worry about this unless you plan to store petabytes.Bulbul
Right, however doesn't this degrade performance to the point that read/write would take a bit longer to commit? If not I'm fine with this. However what I am worrying about my application will be billed as the computing time. So long read/write means more expensive?Machiavelli
I have never heard that longer keys will significantly impact application performance. In the absence of specific benchmark evidence, I am very skeptical.Bulbul
O
0

I've had a similar problem, and the simplest method I've come up with is to use one dummy parent entity. Instead of using XG transactions and inserting another Username entity for every other User entity, just create one dummy parent entity and set that as the ancestor of every User entity you create from there on. I think this method saves a lot of space and data management issues.

Omura answered 24/5, 2014 at 15:9 Comment(1)
The drawback of this is that all User entities end up in one entity group and according to the documentation you can only have 1 write per seond to the entiry group: Datastore documentationCoracoid

© 2022 - 2024 — McMap. All rights reserved.