I don't know if this will help, but I finally figured out how to do parent 
queries using the parent's primary key.  At the moment I don't see what 
advantage there is if you're storing a reference to the parent object in the 
child and using mappedBy in the parent, but here's what I have, in case it 
might be useful.

Here's the child class; note its parentId field and its @Extension.  It fills 
in this field automatically but you have to use either Key or the encoded 
String for the parent's primary key.  Maybe this extension was necessary before 
they added the capability to have a direct reference to the parent (i.e., the 
latter is recent)?

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = 
"true")
public class Platform implements Serializable, Comparable<Platform> {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = 
"true")
    private String id;

    @Persistent
    private String name;

    @Persistent
    private Short ordinal;

    @Persistent(defaultFetchGroup = "true")
    private Facility facility;

    @Element(dependent = "true")
    @Persistent(defaultFetchGroup = "true", mappedBy = "platform")
    private Set<Host> hosts = new HashSet<Host>(0);

    @Element(dependent = "true")
    @Persistent(defaultFetchGroup = "true", mappedBy = "platform")
    private Set<WaitlistEntry> waitlistEntries = new HashSet<WaitlistEntry>(0);

    @Persistent(defaultFetchGroup = "true")
    @Extension(vendorName = "datanucleus", key = "gae.parent-pk", value = 
"true")
    private String parentId;

The parent class is unremarkable:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = 
"true")
public class Facility implements Serializable, Comparable<Facility> {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = 
"true")
    private String id;

    @Persistent
    private String name;

    @Persistent
    private Boolean waitlistEnabled;

    @Element(dependent = "true")
    @Persistent(defaultFetchGroup = "true", mappedBy = "facility")
    private Set<Platform> platforms = new HashSet<Platform>(0);

Then the Platform dao looks like

    public List<Platform> findByFacility(final Facility facility) {
        final Query query = newQuery("parentId == :parentIdParam");

        query.setOrdering("ordinal asc");

        final List<Platform> results = findByQuery(query, facility.getId());

You can probably figure out what it looks like when you use the Facility object 
rather than its id.


James H wrote:
> Consider this test case.  A Person belongs to 1 or more Institutions
> so there's 2 ways you would want to query this.  Query #1: Given a
> particular Person then which Institutions does he belong to?  Query
> #2:  Given a particular Institution then which Persons are members?
> 
> Assume entity Person and its associated child relations will form its
> own entity group and, likewise, entity Institution will form its own
> entity group related to its children.  In order to accommodate large
> amounts of Person and Institution data, I submit that you would need
> "owned" relations of each.
> 
> Therefore, you would need entity PersonInstitutions as an owned child
> relation with Person for Query #1.  Similarly, you would need entity
> InstitutionPersons as an owned child relation with Institution for
> Query #2.
> 
> Also, each of these 2 child entities would contain both a PersonFK and
> a InstitutionFK with appropriate redundant fields ancillary to the
> query requirement of the app.  Again, the embedded FK class avoids
> extra queries that would kill search list performance, etc.  For
> example with Query #2, give me all persons at Baylor that have first
> name James would only need the entity InstitutionPersons.
> 
> So, we accept the fact the design requires redundant data in the
> embedded FK class but at least from a source code perspective we only
> have FK class to manage.
> 
> Is it correct that we would need both "owned" relations or not?  Say
> you had Persons and Institutions from around the world.  I can't
> imagine satisfying the above 2 queries without both "owned"
> relations.  Of course, this means updates to both relations are across
> 2 entity groups and separate transactions.  Another fact we have to
> accept in the design right?
> 
> On Nov 3, 2:22 pm, James H <james.hollier...@gmail.com> wrote:
>> 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)
>> ...
>>
>> 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
-~----------~----~----~----~------~----~------~--~---

Reply via email to