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.
