in principle, I like to work with both, JDO and JPA. but using either of them requires (in most cases) use of the osiv pattern, which in turn results in using something like spring. Keeping the discussions about request and startup performance in mind, apps on GAE shouldn't make use of too many frameworks...
thus, I am thinking about re-designing my persistence architecture based on JDO and Spring... On 27 Jan., 01:40, Jeff Schnitzer <[email protected]> wrote: > Here's the Objectify version of what's described in the video, capable > of a photo-equivalent of "million user fanout": > > class Album { > �...@id Long id; > String name;} > > class PhotoIndex { > �...@id Long id; > �...@parent OKey<Album> album; > Set<OKey<Photo>> photos;} > > class Photo { > �...@id Long id; > String caption; > String blobStoreKey; > > } > > If you want to ask "what albums are this photo in?" (equivalent to > "what messages are waiting for me" in the video), you query like this: > > OQuery<PhotoIndex> query = > createQuery(PhotoIndex.class).filter("photos", photoKey); > List<OKey<Album>> keys = ofy.prepareKeysOnly(query).asList(); > List<Album> albums = ofy.get(keys); > > Jeff > > > > On Tue, Jan 26, 2010 at 4:08 PM, Duong BaTien <[email protected]> wrote: > > 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/BuildingScalableComple... > > >> 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 > > athttp://groups.google.com/group/google-appengine-java?hl=en.- Zitierten > > Text ausblenden - > > - Zitierten Text anzeigen - -- 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.
