Ok Bryce...I'm back. Going to test with your ideas now. In my case, I tend to avoid generic column names like "id" in favor of "bookId" and "chapterId" so I should not have any naming conflicts (at least rarely). Also, my FK embedded classes should not have any collections though I have a feeling they may come up as I get further into it.
I'll just test with Book and owned relation Chapter as you have it here. How do we tell JDO whether a relation is "owned" vs "unowned" by the way? Because I would like to have a child object of each for the testing. Thanks! On Oct 9, 12:06 pm, bryce cottam <bcot...@gmail.com> wrote: > FYI, this video was hugely helpful for me, and this information helps > me decide how to structure my data model to run best on the > app-engine, it's a Google I/O session on how the app-engine big table > implementation works:http://www.youtube.com/watch?v=tx5gdoNpcZM > > > > On Fri, Oct 9, 2009 at 10:46 AM, James H <james.hollier...@gmail.com> wrote: > > > Ylmz, thats how I see it too. Any significant data model will be > > riddled with FKs and since GAE datastore does not support Joins you > > have NO choice but to denormalize your data to meet the needs of your > > app queries. The Cottam Pattern above allows best management of > > source to accomplish this denormalization. > > > I assume the simple example you are referring to either only stores > > the Keys in the physical table (which would be insufficient for app > > queries) or stores the whole record (which would be massive overkill). > > > Does that make any sense? > > > On Oct 8, 4:46 am, bryce cottam <bcot...@gmail.com> wrote: > >> yes, I think the point that we are making is that we are trying to > >> managed "un-owned" relationships :) > >> You are describing owned relationships, which I use as well, but in > >> many cases, I really want un-owned relationships. For a variety of > >> reasons really, one of which is that the children I have in my > >> collection get get rather big, and there is a cap on the number of > >> writes that can happen on an entity group. So, in come cases it's > >> better to model the relationships as foreign keys. > > >> The problem comes in when you try to manage your data. It's a pretty > >> common suggestion from the app-engine team to denormalize, we're just > >> trying to come up with a way to denormalize and minimize code > >> duplication etc. Denormalizing will let you query better/faster etc. > >> but can create headaches when trying to update a single field which is > >> mirrored on several other entities. > > >> For instance, you could have an Employee that works for several > >> departments in a company. It's the same Employee, so it should be a > >> single record. So, in this case you'd have a Company, Division and > >> Employee. A Company "owns" it's Divisions and it also "owns" it's > >> Employees, yet a Division "owns" it's Employees as well. So, where > >> does the collection of Employees live? On the Company, or the > >> Division? If it's the Division, then you can't share employees with > >> other divisions (unless you duplicate the Employee record). If the > >> Company owns the Employee, then you have to make some way for the > >> Division to know who's in it. You could do this by putting a > >> collection of Division Key objects on an Employee record, or a > >> collection of Employee Keys on a Division record. Yet, this doesn't > >> allow for simple querying, like "select all employees that work in a > >> division located in New York and has less than 20 people in it". Or, > >> "select all divisions who have an employee named Fred". > > >> you can do queries like this if you denormalize the data though :) > > >> On Thu, Oct 8, 2009 at 3:35 AM, ylmz <yilmazhuse...@gmail.com> wrote: > > >> > may I suggest different kind of desing > >> >http://code.google.com/appengine/docs/java/datastore/relationships.html, > >> > in this document it suggests to use collection types to design one to > >> > many relation ships. > >> > and it works pretty well actually. when you use a collection type. app > >> > engine does not really use the original colection type you used. > >> > instead > >> > it uses its own replacement. so if you want to add a new employee to > >> > the company you just add a new one to the list. it automatically added > >> > to datastore. > >> > and if I understand right, when you get a company you dont get all the > >> > employees inside. you only get a collection type which is actulally > >> > empty but look like it has employees inside. > >> > so when you get any element from collection type > >> > it pulls that record from datastore. > >> > there is also some collection types that excepts unique values. > >> > Is there a spesific reason you don't use collections that I didn't > >> > understand? > > >> > On Oct 7, 4:16 am, James H <james.hollier...@gmail.com> wrote: > >> >> Wow, this is majorly useful...can't wait to try it out!!! For the > >> >> life of me I can't figure out why this problem domain has NOT already > >> >> been exhausted in this Group since denormalization is a requirement > >> >> with this technology for any significant business application! > > >> >> I believe your example should be placed in a section on how to handle > >> >> Advanced Relations w/Denormalization in this section of the docs: > > >> >>http://code.google.com/appengine/docs/java/datastore/relationships.html > > >> >> Great work, Bryce! I'll see if I can break it :) > > >> >> As for our other achilles' heel, that being Distributive > >> >> Transactions...do you think the Open Source team will deliver any time > >> >> soon? I worry about contention in that solution since everything is > >> >> concentrated into 1 table - the DT instruction table... Meanwhile, > >> >> I'm thinking about queuing 2nd and N-phase transactions to the Task > >> >> Queue, yep its a bandaid. > > >> >> On Oct 6, 6:29 pm, bryce cottam <bcot...@gmail.com> wrote: > > >> >> > oh, I should clarify, the @ReferencedField, is an annotation I wrote, > >> >> > it's not part of any library or anything: > >> >> > @Retention(RetentionPolicy.RUNTIME) > >> >> > @Target({ElementType.FIELD, ElementType.METHOD}) > >> >> > public @interface ReferencedField { > >> >> > public String srcField(); > > >> >> > } > >> >> > On Tue, Oct 6, 2009 at 5:19 PM, bryce cottam <bcot...@gmail.com> > >> >> > wrote: > >> >> > > Thanks for the update Diana, > >> >> > > I hadn't thought to look in this forum for a "series" nice moves > >> >> > > :) > > >> >> > > I've gotten some pieces of this to work out well so far. This is an > >> >> > > overview of what I have (using the Book/Chapter example) > > >> >> > > @PersistenceCapable(identityType=IdentityType.APPLICATION, > >> >> > > detachable="true") > >> >> > > public class Book { > > >> >> > > �...@primarykey > >> >> > > �...@persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) > >> >> > > private Key id; > > >> >> > > �...@persistent > >> >> > > private String title; > >> >> > > �...@persistent > >> >> > > private String isbn; > > >> >> > > // getters and setters > >> >> > > } > > >> >> > > @PersistenceCapable(detachable="true") > >> >> > > public class BookFK { > >> >> > > �...@persistent > >> >> > > private Key id; > >> >> > > �...@persistent > >> >> > > private String title; > >> >> > > �...@persistent > >> >> > > private String isbn; > >> >> > > // getters and setters > >> >> > > } > > >> >> > > @PersistenceCapable(identityType=IdentityType.APPLICATION, > >> >> > > detachable="true") > >> >> > > public class Chapter { > >> >> > > �...@primarykey > >> >> > > �...@persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) > >> >> > > private Key id; > > >> >> > > �...@persistent > >> >> > > private String title; > >> >> > > �...@persistent > >> >> > > private int numPages; > > >> >> > > �...@persistent > >> >> > > �...@embedded > >> >> > > private BookFK book; > > >> >> > > // getters and setters > >> >> > > } > > >> >> > > so, this looks promising, but we still have the problem of name > >> >> > > collissions > >> >> > > (the "title" and "id" fields in this case). > >> >> > > in order to resolve this, we put a "members" field in our @Embedded > >> >> > > annotation. However, I've noticed that JDO seems to like it better > >> >> > > if you > >> >> > > itemize all fields of an embedded class if you itemize any of them: > > >> >> > > �...@persistent > >> >> > > �...@embedded(members= { > >> >> > > �...@persistent(name="id", colum...@column(name="bookId")), > >> >> > > �...@persistent(name="title", > >> >> > > colum...@column(name="bookTitle")), > >> >> > > �...@persistent(name="isbn") > >> >> > > }) > >> >> > > private BookFK book; > > >> >> > > either that, or we need to rename the fields in our BookFK class: > > >> >> > > public class BookFK { > >> >> > > �...@persistent > >> >> > > private Key key; > >> >> > > �...@persistent > >> >> > > private String bookTitle; > >> >> > > �...@persistent > >> >> > > private String isbn; > >> >> > > } > > >> >> > > I lean towards the latter when it's simple (like in the "id" vs > >> >> > > "key" > >> >> > > example. The idea here, is that you're going to be querying on > >> >> > > these > >> >> > > fields, so you probably doing want to make them hard to remember. > >> >> > > It'd be > >> >> > > great if you could always have the fields in the FK class be the > >> >> > > same name > >> >> > > as the fields in the mirrored Entity class. Then you'd have > >> >> > > queryies like > >> >> > > this: > >> >> > > select from Chapter where book.id = 1234 and book.title = "The Art > >> >> > > of JDO on > >> >> > > the App-Engine" > >> >> > > but in our (my) case this get's modified to: > >> >> > > select from Chapter where book.key = 1234 and book.bookTitle = "The > >> >> > > Art of > >> >> > > JDO on the App-Engine" > > >> >> > > I don't so much mind the naming difference, but some people may get > >> >> > > annoyed > >> >> > > by it :) > > >> >> > > So, what we've got above works enough, but the problem is setting > >> >> > > fields on > >> >> > > the BookFK object from the mirrored Book object. We could have a > >> >> > > single > >> >> > > block of code that does stuff like this: > > >> >> > > public static BookFK createFK(Book book) { > >> >> > > BookFK fk = new BookFK(); > >> >> > > fk.setKey(book.getId()); > >> >> > > fk.setBookTitle(book.getTitle()); > >> >> > > fk.setIsbn(book.getIsbn()); > >> >> > > return fk; > >> >> > > } > > >> >> > > and that's fine, it's pretty darn manual, but it is a single place > >> >> > > where > >> >> > > things get updated. > >> >> > > I found that I could centralize that set/get code by making a simple > >> >> > > annotation: > >> >> > > @ReferencedField > > >> >> > > so our BookFK turns into this: > > ... > > read more »- Hide quoted text - > > - Show quoted text - --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---