Hi Jeff:

I am here again and have put sometime in Objectify. Thanks for taking
pain at different design patterns. Please let the list known your effort
in the good idea #2, especially in the social graph set intersections
and union.

Duong BaTien
DBGROUPS and BudhNet


On Tue, 2010-01-26 at 14:19 -0800, Jeff Schnitzer wrote:
> On Mon, Jan 25, 2010 at 11:52 PM, John Patterson <[email protected]> 
> wrote:
> >
> > This is why you configure what type of relationship is used using: @Embed,
> > @Entity(PARENT), @Entity(CHILD) or @Entity(INDEPENDENT)
> > So you have the flexibility to choose configuration _without_ rewriting your
> > code.  Very important difference.
> 
> The problem is that it *isn't* as simple as just changing an
> annotation.  Not in appengine, at any rate.  It works in the simple
> case (good for demos and sample apps), but you start to notice edge
> cases:
> 
>  * In some representations you can add a Photo to an Album in a
> transaction, in some representations you can't.
>  * In some representations, multiple queries are required to fetch a
> fetch an Album containing a Photo.
>  * Each representation has a completely different query syntax.
> 
> Twig exposes the datastore Query object, which means the developer
> gets the full brunt of this exposure.
> 
> I don't want to say that it isn't possible to build a system that
> abstracts entities into a sophisticated object graph - clearly, we
> have JDO & JPA.  What I'm saying is that the people who created JDO &
> JPA are not idiots (although I do think the creators of JDO's
> annotations are aesthetically challenged).  The reason JDO has all
> that complexity and endless configuration and query languages and
> fetch groups and proxies and detaching and whatnot is because that's
> what you need to abstract an arbitrary entity graph.
> 
> > Currently the first type of representation is not an option.  I do want to
> > add this as it makes very large collections that change often much more
> > efficient.  When it is added you could reconfigure your data schema by
> > changing a single annotation.  Such a change in Objectify would require the
> > developer to rewrite their entire data layer
> 
> You can never just reconfigure your data schema with a single
> annotation, both for the reasons above and because you probably have
> real-world data to migrate.  And real-world constraints demand a
> particular schema!
> 
> Let's actually answer the original poster's question - how do you
> model a photo album?  I hope he's still listening :-)
> 
> The first question is how you should model it in the datastore?  I'll
> use Objectify's syntax  here because it corresponds directly to the
> datastore representation.
> 
> Actually, let's start by describing how you SHOULDN'T model a photo album.
> 
> -----
> 
> BAD IDEA #1:
> 
> class Album {
>     @Id Long id;
>     String name;
>     List<OKey<Photo>> photos;
> }
> class Photo {
>     @Id Long id;
>     String caption;
>     String blobStoreKey;    // key to GAE's blobstore
> }
> 
> Fetching photos in an album (again, Objectify syntax but equivalent to
> the datastore operation) is:
> 
> List<Photo> fetched = ofy.get(album.photos);
> 
> There are two reasons why this is a bad idea:
> 
>  1) You now have a hard limit of 5,000 photos per album, established by GAE.
> 
>  2) Every time you load an Album, you must load the entire set of
> Photo keys.  Want to generate a list of Album names?  You have to load
> all that key data, orders of mangitude more data than what you want.
> 
> -----
> 
> BAD IDEA #2:
> 
> class Album {
>     @Id Long id;
>     String name;
> }
> class Photo {
>     @Id Long id;
>     @Parent OKey<Album> album;
>     String caption;
>     String blobStoreKey;
> }
> 
> This stores the Photo with the Album embedded in the Photo's Key as an
> ancestor, making Photo part of the Album's entity group.  At first
> glance, this seems kinda cool and you can now do transactions across
> Albums and Photos.
> 
> Fetching photos in an album:
> 
> OQuery<Photo> query = createQuery(Photo.class).ancestor(albumKey);
> List<Photo> fetched = ofy.prepare(query).asList();
> 
> The problem is what happens when you want to move a Photo from one
> Album to another.  You can't just change the parent.  You must delete
> the Photo entity and create a whole new Photo entity with the new
> parent Album.  And if the Photo has Comments or other referring
> entities?  All those comments need to be repointed at the new Photo.
> A mess.
> 
> -----
> 
> GOOD IDEA:
> 
> class Album {
>     @Id Long id;
>     String name;
> }
> class Photo {
>     @Id Long id;
>     OKey<Album> album;
>     String caption;
>     String blobStoreKey;
> }
> 
> Fetching photos in an album:
> 
> OQuery<Photo> query = createQuery(Photo.class).filter("album", albumKey);
> List<Photo> fetched = ofy.prepare(query).asList();
> 
> You can now move Photos between Albums easily and you can load/query
> Albums efficiently.
> 
> -----
> 
> GOOD IDEA #2:
> 
> I considered writing something about index entities as described here:
> http://code.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html
> 
> This is what you would probably want to use if a Photo can live in
> more than one Album.  But this message is long enough already.
> 
> -----
> 
> So now you're thinking, that's just the representation in the
> datastore, wouldn't you rather have a entities that hide all that and
> provide an interface like this:
> 
> class Album {
>     @Id Long id;
>     String name;
>     List<Photo> photos;
> }
> class Photo {
>     @Id Long id;
>     String caption;
>     String blobStoreKey;
> }
> 
> This is one of those things that looks good in a simple demo but in
> the real world breaks down.  Twig doesn't currently support mapping
> this to GOOD IDEA.  If Twig did support this, it would also need to
> support lazy loading of the collection with a proxy - otherwise you
> have a worse problem than BAD IDEA #1!  And now, if this list is a
> proxy, serialization becomes an issue - you need some sort of
> detaching mechanism.
> 
> ...and then you have JDO.
> 
> I hope this message doesn't sound like "Twig is bad" - it's not, and
> it does (and probably always will) do things that Objectify does not.
> I just want to discourage the notion that you can easily work on
> Appengine without using the Key class.  Judging by the official sample
> code, this isn't even easy using JDO!
> 
> 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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to