Bryce, I tried another use of your "embedded class" related to Audit fields on an Entity. For consistency in approach to Auditing entity data, typically you would add the following 4 fields to each entity in your design: createBy, createdDate, updatedBy, and updatedDate. I thought I'd place these 4 fields in an embedded class to be used by every entity as a Best Practice to manage these 4 fields. But, I noticed when I tried this on the first entity kind it left the embed null after a standard Query. The code looks like this:
@PersistenceCapable(identityType = IdentityType.APPLICATION) public class Member { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key memberId; @Persistent private Key referringMemberId; @Persistent private String memberType; ... @Persistent @Embedded private DataAudit dataAudit; } @PersistenceCapable(embeddedOnly="true") public class DataAudit { @Persistent private Key createMemberId; @Persistent private Date createDate; @Persistent private Key updateMemberId; @Persistent private Date updateDate; public DataAudit() throws Exception { createMemberId = null; createDate = null; updateMemberId = null; updateDate = null; } // getters/setters } Sample query logic for all members: List<Member> list = pm.newQuery(Member.class).execute(); So each Member in the list is valid, except member.dataAudit is null and I assume the query engine would populate dataAudit along with its fields from the query automatically...as in the case with the embeds from your examples. Any ideas? On Nov 5, 1:40 pm, bryce cottam <bcot...@gmail.com> wrote: > here's a really good talk about how objects are mapped into the > BigTable datastore and how relationships are actually represented in > the > system:http://sites.google.com/site/io/under-the-covers-of-the-google-app-en... > this sort of highlites how relationships actually work in BigTable > (which is quite different than they work in an RDB). > > here is another one from Max Ross where he advocates denormalization > for query > optimization:http://code.google.com/events/io/2009/sessions/SofterSideofSchemas.html > he kind of goes into how the BigTable datastore is simply schema-less. > Very interesting stuff. > > hope that helps. > -bryce > > > > On Thu, Nov 5, 2009 at 12:34 PM, Rusty Wright <rwright.li...@gmail.com> wrote: > > > Good points. In my case, so far, the copied objects are small and not > > complicated, which is why my method appealed to me. > > > I feel like there's some fundamental concept that I'm not getting and it > > has to do with how objects are mapped onto the Big Table data store. > > Watching the videos from Google I/O, those guys just wave their hands and > > make it sound like it's all so easy, if you know what you're doing. > > > bryce cottam wrote: > >> I don't think that duplicating the whole Department object as a child > >> of a Person is all that good of an idea. First off, if the Department > >> object gets complicated and has it's own child objects all that data > >> will be living on the Person, which isn't really needed. The whole > >> reason for the FK style classes is to pull over only those fields you > >> would want to query on when selecting a Person object like: > >> select from Person where department.name == "ABC" > >> (which is something you cannot do otherwise) > > >> So, I've found that either having a list of Key (or encoded string > >> ids) on a Person instance is usefull (when you are not wanting to > >> query on fields of the Department when selecting a Person, > >> Or having a list of lightweight copies of a Department (as opposed to > >> the whole Department object) > >> It seems very natural to me to determine equality of two persisted > >> objects by comparing their Key instance, rather than simply their > >> name. For one reason; it's somewhat difficult to ensure uniqueness > >> for arbitrary fields on an object in the GAE unless that fields is > >> being used to create the key (like an email address or something), if > >> you are using auto-generated Keys, this isn't really an option. > > >> So, assuming you have the lightweight FK style object as a child of > >> the Person class, then when the source of truth changes (i.e. the real > >> Department instance), you'd need to find all lightweight FK style > >> copies of that instance and update them accordingly. This is part of > >> the whole root of this discussion: how do you do this in a way that > >> minimized code duplication and boilerplate code blocks (like > >> constructors that manually copy fields from getters to setters etc.) > > >> The solution I've been working with is the ligthweight FK style "copy" > >> of the real instance of an object, and some simple reflection to map > >> fields from the real object to the lightweight FK "copy". > > >> As far as detachable="true|false" my main concern with that right now > >> is how the GWT RPC serializer handles detachable entities (i.e. it > >> doesn't handle them well). There are certainly advantages to > >> detaching an object, however, if the updates to the object are > >> happening on the server, then there is no need to detach the object. > > >> On Thu, Nov 5, 2009 at 1:09 AM, Rusty Wright <rwright.li...@gmail.com> > >> wrote: > >>> I think this is an important point. The light bulb went off over my head > >>> after watching this video. This is what he calls a property list. For > >>> me it was also a good example of how to think about denormalizing, which > >>> comes up repeatedly. > > >>> So instead of the usual OO way of thinking of a department etc. > >>> aggregating people, turn it on its head and look at it as a person has a > >>> property, which is their department, and in this example, they can be in > >>> multiple departments so it's a list of departments, a property list. As > >>> you point out, the queries for this are slick. And it sounds like you > >>> don't even need the list of people in the department; it's redundant. > > >>> I'm still puzzled about what to do when a property value changes; for > >>> example, suppose the department named the Ministry of Propaganda changes > >>> its name to the Ministry of Disinformation. Does the property list on > >>> Person contain a list of Department objects, or a list of Department Key > >>> objects? I'm thinking the former, Department objects. If we have the > >>> Department class configured with detachable="false", each time you fetch > >>> a Department object (matching on its name let's say), you get a new > >>> unparented Department object, which you add to the Person's department > >>> list, whereupon it becomes parented by Person. The fetched Department > >>> object is essentially a clone. (That's assuming I understand how it > >>> works when you have detachable="false"; it's sort of like the singleton > >>> pattern.) As part of fetching the cloned Department object, the > >>> Department class has a masterKey field, type Key, which you set to the > >>> Key of the Department in the table, the one it was cloned from. So > > whe > >>> n the Department's name changes, the query to get all its cloned > >>> Departments could be simple and quick. But now I'm fuzzy on how you > >>> change the master Department's name; since it's detachable="false" we > >>> can't fetch it and update it and save it back, so I guess we have to > >>> replace it in the master table and then replace all of its clones in all > >>> Person lists? > > >>> bryce cottam wrote: > >>>> ah, gottcha, well there is actually a really good google i/o talk on > >>>> using list/collections and how to optimize them. I generally am using > >>>> "owned" lists for smaller collections,and un-owned ones are > >>>> represented by the child object containing an FK type class as a > >>>> "backwards pointer" to the parent. If I want to get all the children > >>>> for a given parent, I can query "select from Child where parent.id = > >>>> :myParentId". Of course, the Child.parent field needs to be embedded > >>>> in order to query off it in this manner. So, in your case I'd imagine > >>>> a Person would be in a handful of Institutions, but an Institution > >>>> could have tons and tons of Person instances in it. So I'd think > >>>> you'd want to keep the relationship defined in the Person.institutions > >>>> collection, and anytime you need to query "who's in InstitutionX?" you > >>>> can do the query against the Person data class. There is a rather > >>>> slick way to do this in JDO: > > >>>> String filter = "institutions.contains(inst) && inst.id == > >>>> :myInstitutionId"; > >>>> Query q = pm.newQuery(Person.class, filter); > >>>> q.declareVariables("Institution inst"); > >>>> List<Person> peopleInMyInstitution = query.execute(myInstitutionId); > > >>>> the key is this line: > >>>> String filter = "institutions.contains(inst) && inst.id == > >>>> :myInstitutionId"; > >>>> where you're (basically) inspecting fields of individual values found > >>>> in the collection "institutions" in JDOQL. > >>>> There are slicker ways of getting the results back (like a KEY_ONLY > >>>> query) which can help performance. > > >>>> if course, if you don't care about querying against fields of the > >>>> Institution, then changing the Person.institutions model to just be a > >>>> List<Key> or List<String> would do you fine, in that case your query > >>>> just becomes: > >>>> String filter = "institutions.contains(:myInstitutionId)"; > >>>> Query q = pm.newQuery(Person.class, filter); > >>>> List<Person> peopleInMyInstitution = query.execute(myInstitutionId); > > >>>> (thus removing the declareVariables call and simplifying the filter > > >>>> here is the i/o session, it's got some good tips: > >>>>http://code.google.com/events/io/2009/sessions/BuildingScalableComple... > > >>>> hope that helps! > >>>> -bryce > > >>>> On Wed, Nov 4, 2009 at 11:50 PM, James H <james.hollier...@gmail.com> > >>>> wrote: > >>>>> Thanks Bryce...here's the earlier post: I no longer get the error > >>>>> stack above...I just added > >>>>> embeddedOnly="true" to the PersistanceCapable tag in BookFk class. > >>>>> You're right, I could use the collection technique on the FKs but I > >>>>> wonder the pros/cons of such collections on what could be very large > >>>>> collections. For example, say an Institution like Baylor with 25,000 > >>>>> Persons? Guess its > >>>>> a matter of using "owned" for small Sets versus "unowned" for large > >>>>> Sets of data right? > > >>>>> On Nov 5, 12:36 am, bryce cottam <bcot...@gmail.com> wrote: > >>>>>> sorry, I meant "1:45", not 1:15 > > >>>>>> On Wed, Nov 4, 2009 at 11:36 PM, bryce cottam <bcot...@gmail.com> > >>>>>> wrote: > >>>>>>> yeah, the Key class hasn't caused me any issues. I've actually > >>>>>>> created an appengine-utils gwt module that makes it easier to > >>>>>>> serialize GAE data types over GWT RPC channels > >>>>>>> (www.resmarksystems.com/code/app-engine). > >>>>>>> I think I'm in a different time zone than you James, I see quite a few > >>>>>>> posts from you on Nov 4, but I don't see one at (or really near) 1:15, > >>>>>>> can you re-state what you'd like me to review? I'd be happy to help > >>>>>>> where I can. > >>>>>>> thanks! > >>>>>>> -bryce > >>>>>>> On Wed, Nov 4, 2009 at 11:30 PM, James H <james.hollier...@gmail.com> > >>>>>>> wrote: > >>>>>>>> Bryce, double-check me on my Nov 4, 1:45pm post. > >>>>>>>> Bryce/Rusty, I'm getting the sense that if I don't need a natural key > >>>>>>>> like email address then I should just use plain Key as the type and > >>>>>>>> let GAE generate the full value including parent key for entity group > >>>>>>>> objects. Otherwise, if I choose to use a natural key like an email > >>>>>>>> address then I would use the encoded Key. Regardless of approach, > >>>>>>>> the > >>>>>>>> type > > ... > > 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 -~----------~----~----~----~------~----~------~--~---