I'm working on a multi-user application where I'm using my own 
authentication / account scheme, but am running into trouble structuring 
accounts in GAE storage. Here's where I started and got tripped up:

- I'd like each user be a root level entity, and have all of the entities 
for that user be child entities, since transactions are almost always done 
on a single user.

- I'd like the username for users to be their email address, which they can 
change at any time, but each user should have a system-assigned integer ID 
that never changes.

Given this, I started creating Account entities at the root level, each 
with an "email" property containing their email address. My first problem 
came immediately, when trying to create an Account as follows:

public boolean createAccount(final Account ac) {
    final DatastoreService ds = DatastoreServiceFactory.getDatastoreService
();

    final Transaction txn = ds.beginTransaction();
    try {
        // see if an account with the same email already exists
        final Query q = new Query("Account");
        q.addFilter("email", Query.FilterOperator.EQUAL, ac.getEmail());

        final PreparedQuery pq = ds.prepare(txn, q);
        final boolean bCreated;

        if (0 < pq.countEntities(FetchOptions.Builder.withLimit(1))) {
            bCreated = false;
        } else {
            ds.put(EntityFactory.create(ac)); // EntityFactory just creates 
an entity of kind "Account" with the right fields set
            bCreated = true;
        }

    txn.commit();
    return bCreated;
    } finally {
        if (txn.isActive())
            txn.rollback();
    }
}


The problem is, I can't query and update root level entities in a 
transaction, because that query doesn't contain an ancestor query, so 
there's no way for me to atomically check that an Account with a given 
email address doesn't exist, then create the account. I get 
"java.lang.IllegalArgumentException: Only ancestor queries are allowed 
inside transactions.". How do I solve this, given the following 
restrictions?

- I don't want the email address to be the key for the entity, because then 
a user's email address can't change without copying their entire entity 
tree.

- I don't want users to have a separate username from their email address 
that's used as the entity key, as they tend to forget usernames, so I find 
their email address to be convenient.

- I don't want to create a dummy parent entity that all Accounts are under, 
because that would force all users to be in the same entity group, which 
would make transaction concurrency poor.

Any thoughts?

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/google-appengine/-/5TUz9xKMX8YJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.

Reply via email to