Ah yes good point re the separate entity groups not allowing a query.

On 23 Feb 2010, at 15:50, Jeff Schnitzer wrote:

If you have an account that looks like this:

class Account {
   @Id Long id;
   String email;
}

Two people can create Accounts at the same time with the same email
address.  Or someone could change their email address at the same time
someone creates an account.  Or two people could change their email to
the same address at the same time.  You get the picture.

You can't use transactions because the Account objects are in separate
entity groups.  Nothing prevents the same email address from being
attached to two accounts, so you might get a collision.  Since login
is done by email address, one of these users is screwed.

Jeff

On Mon, Feb 22, 2010 at 10:55 PM, John Patterson <jdpatter...@gmail.com > wrote:
I don't see what extra protection storing an email as a separate entity buys you. If you store the same email address twice you do not get an exception thrown like in an RDBMS... it just silently overwrites the existing one. In either case, storing the email as a key or as a field, you would need to do a query (or get) in a transaction to be sure you were not going to overwrite
an existing record with the same email.

On 23 Feb 2010, at 13:37, Jeff Schnitzer wrote:

I don't think we're disagreeing - user-defined keys are the only way
to enforce uniqueness.  I was just trying to point out that
user-defined longs work just as well for enforcing uniqueness as
user-defined Strings if your natural key is numeric.  There's no
reason to convert it to a String.

I don't personally think there's anything wrong with carefully chosen
natural keys.  Domain name in your example is a great natural key.

Accounts with an email address is a little weirder.  You want two
things:  Accounts should be able to change their email addresses (so
using the email as the Account key is a bad idea) but you also want to
enforce uniqueness of the email address field (users use it to log
in).  So the appropriate model for this in appengine is probably to
have Account and Email as separate entities, Account with a generated
id and Email with a tautological natural key.

...which provides one more illustration of why the JDO claim of
"transparent persistence" across multiple datastores is bogus. You'd
never do this in an RDBMS.

Jeff

On Mon, Feb 22, 2010 at 8:09 PM, Max Ross (Google)
<maxr+appeng...@google.com> wrote:

Jeff,

I agree with the majority of your design philosophy and the advice you're
dispensing, but I still disagree with you on one pretty fundamental
point.
If I'm understanding your argument correctly, you're saying that best practices for primary key management don't involve user-defined strings, therefore user-defined strings aren't a necessary feature, but I think
this
ignores a pretty basic usage of uniqueness constraints. Let's say you're
a
domain registrar, you're building your registration workflow on App
Engine,
and you need to guarantee that a domain name can only be claimed once.
 If
you use a numeric id mapped to the domain name you run the risk of
letting
two users reserve the same domain, and if you're a domain registrar
that's
really really bad. There's no natural key we can bring in here. Whether
we
as application developers run into them frequently or not, there exists a class of problems where a user-defined string pk is a necessary part of
the
solution.

Regards,
Max

On Mon, Feb 22, 2010 at 1:52 PM, Jeff Schnitzer <j...@infohazard.org >
wrote:

On Mon, Feb 22, 2010 at 1:19 PM, Max Ross (Google)
<maxr+appeng...@google.com> wrote:

user-defined long-id keys are not quite as easily used. You either
need
to
commit to not letting the datastore generate ids for that kind or you
need
to reserve a batch of ids using the DatastoreService.allocateIds
method.
Otherwise you run the risk of a silent collision. There is no such
risk
with user-defined string keys.

Right, but if the user has a natural key (long, String, whatever) they
won't be using the generator anyways.  There are plenty of natural
long keys in the world... facebook userid being a popular one.

FWIW, Objectify makes the distinction between ids of type Long, which
can be null and thus autogenerated, and long (the primitive) which
cannot be autogenerated. I really hadn't intended to plug Objectify
here, really!

Valid point about renaming, but going back to the example I provided,
the
datastore does not distinguish between inserts and updates. The only
way
you can guarantee that an entity was inserted, and therefore the only
way
you can guarantee the uniqueness of the name, is to use a user- defined
key.
If you're mapping id to name it will be possible to create two entities
with
the same name. It's of course up to you to decide how important this
is
to
defend against, but without the ability to provide your own id you
wouldn't
get to make this choice, and without the ability to provide your own
string
id you wouldn't be able to add some application-specific meaning to
this
choice.

I totally agree with you WRT user-defined vs generated values, I just
don't see anything wrong with using the long id as a user-defined
value.  Just make sure you never ask for a generated one.  Seems
pretty straightforward.

Jeff

--
You received this message because you are subscribed to the Google
Groups
"Google App Engine for Java" group.
To post to this group, send email to
google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.


--
You received this message because you are subscribed to the Google Groups
"Google App Engine for Java" group.
To post to this group, send email to
google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.


--
You received this message because you are subscribed to the Google Groups
"Google App Engine for Java" group.
To post to this group, send email to
google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.


--
You received this message because you are subscribed to the Google Groups
"Google App Engine for Java" group.
To post to this group, send email to google-appengine-java@googlegroups.com .
To unsubscribe from this group, send email to
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.



--
You received this message because you are subscribed to the Google Groups "Google App Engine for Java" group. To post to this group, send email to google-appengine-java@googlegroups.com . To unsubscribe from this group, send email to google-appengine-java+unsubscr...@googlegroups.com . For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=en .


--
You received this message because you are subscribed to the Google Groups "Google 
App Engine for Java" group.
To post to this group, send email to google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to