Max Ross said...
    ...Please post your question on the Google Group for GAE Java (the
link is in the App Engine Links section on the right) along with your
model objects and the code you're using to query for the child
objects....
================================================================

I have been attempting to do an owned one-to-many and have followed
the example here. I have also tried for more than 10 hours
experimenting with sight variations (looking at other examples) and
using the debugger. I save the parent with a long list of children
with no erros. No matter what I do it when I query and get the parent,
the child list comes back empty. My datastore now has 10s of parent
records.

    One difference is that my fields are public. Is that the problem?
I don't think it could be.

    Another difference is that when I use:
    public List chapters = new ArrayList();

When I try not using generics on the ArrayList I get the following
runtime error:
    Jan 12, 2010 8:56:59 PM
com.google.appengine.tools.development.ApiProxyLocalImpl log
    SEVERE: [1263329819732000] javax.servlet.ServletContext log:
Exception while dispatching incoming RPC call
    com.google.gwt.user.server.rpc.UnexpectedException: Service method
'public abstract java.lang.String lt.client.GreetingService.greetServer
(java.lang.String)' threw an unexpected exception:
org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException:
The class "The class "lt.server.Book" is not persistable. This means
that it either hasnt been enhanced, or that the enhanced version of
the file is not in the CLASSPATH (or is hidden by an unenhanced
version), or the Meta-Data/annotations for the class are not found."
is not persistable. This means that it either hasnt been enhanced, or
that the enhanced version of the file is not in the CLASSPATH (or is
hidden by an unenhanced version), or the Meta-Data for the class is
not found.

I don't get the ClassNotPersistenceCapableException runtime error if I
declare the list as:
    public List⟨Chapter⟩ chapters = new ArrayList〈Chapter〉
();
However, I am unable to query and get back any of the items that were
in the list.

I have also tried
    @Persistent (defaultFetchGroup = "true")
    private Book theBook;
    in the child, and that gets this warning:
    Jan 12, 2010 8:06:34 PM
org.datanucleus.store.appengine.MetaDataValidator warn
    WARNING: Meta-data warning for lt.server.Lyric.theBook: The
datastore does not support joins and therefore cannot honor requests
to place child objects in the default fetch group. The field will be
fetched lazily on first access. You can modify this warning by setting
the datanucleus.appengine.ignorableMetaDataBehavior property in your
config. A value of NONE will silence the warning. A value of ERROR
will turn the warning into an exception.

To clarify the above, I think I have tried everything except private
fields and a non-generic ArrayList.  I have never been able to get the
child records back, although I get the parent.

(I have edited the above to change from Song to Book and Lyric to
Chapter to agree with your example)

Here is my query code:
        public lt.client.Song getSong(String input) {
                lt.client.Song result = null;
                Song theSong = null;
                PersistenceManager pm = pmfInstance.getPersistenceManager();
                try {
                        String query = "select from " + Song.class.getName()
                                        + " where name == lastNameParam "
                                        + " parameters String lastNameParam ";
                        List<Song> songs = (List<Song>) 
pm.newQuery(query).execute(input);
                        for (Song aSong : songs)
                                theSong = aSong;
                        List<lt.client.Lyric> ll = new 
ArrayList<lt.client.Lyric>();
                        if (theSong != null) {
                                if (theSong.lyrics != null)
                                        for (Lyric l : 
(List<Lyric>)theSong.lyrics) {
                                                ll.add(new 
lt.client.Lyric(l.measure, l.words));
                                        }
                                if (ll.size() == 0) {
                                        List<String> emptyLyric = new 
ArrayList<String>();
                                        emptyLyric.add("emptyLyric");
                                        ll.add(new 
lt.client.Lyric("EmptyMeasure", emptyLyric));
                                }
                                result = new lt.client.Song(theSong.name, ll);
                        }
                } finally {
                        pm.close();
                }
                if (result != null)
                        return result;
                return new lt.client.Song("Song not found",
                                new ArrayList<lt.client.Lyric>());
        }
}

Here are my classes:

package lt.server;

import java.io.*;
import java.util.*;

import javax.jdo.annotations.*;
import javax.jdo.*;
import javax.persistence.Entity;

import com.google.appengine.api.datastore.Key;

@PersistenceCapable(identityType = IdentityType.APPLICATION,
detachable = "true")
public class Song implements Serializable {
        @SuppressWarnings("unused")
        @PrimaryKey
        @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
        private com.google.appengine.api.datastore.Key key;

        @Persistent
        public String name;

        @Persistent(mappedBy = "theSong")
        @Element(dependent = "true")
        //public List<Lyric> lyrics = new ArrayList<Lyric>();
        public List lyrics = new ArrayList();

        public void initSong(PersistenceManager pm, Reader input) {
                StreamTokenizer st = new StreamTokenizer(input);
                name = "";
                st.resetSyntax();
                st.wordChars('\u0021', '\u00FE');
                st.whitespaceChars('\u0000', '\u0020');
                st.eolIsSignificant(true);
                st.slashSlashComments(false);
                List<String> words = new ArrayList<String>();
                String measure = "";
                try {
                        while (st.nextToken() != StreamTokenizer.TT_EOL
                                        && st.ttype != StreamTokenizer.TT_EOF) {
                                name += (st.sval + " ");
                        }
                        if (st.ttype != StreamTokenizer.TT_EOF) {
                                while (st.nextToken() == StreamTokenizer.TT_EOL)
                                        ;
                                if (st.ttype != StreamTokenizer.TT_EOF) {
                                        if (st.sval.substring(0, 
1).equals("|")) {
                                                if (st.sval.length() > 1)
                                                        measure = 
st.sval.substring(1);
                                                else {
                                                        while (st.nextToken() 
== StreamTokenizer.TT_EOL)
                                                                ;
                                                        if (st.ttype != 
StreamTokenizer.TT_EOF) {
                                                                measure = 
st.sval;
                                                        }
                                                }
                                        } else {
                                                st.pushBack();
                                                measure = "";
                                        }
                                        if (st.ttype != StreamTokenizer.TT_EOF) 
{
                                                boolean pendingLyric = false;
                                                while (st.nextToken() != 
StreamTokenizer.TT_EOF) {
                                                        if (st.ttype == 
StreamTokenizer.TT_EOL) {
                                                                pendingLyric = 
true;
                                                                while 
(st.nextToken() == StreamTokenizer.TT_EOL)
                                                                        ;
                                                        }
                                                        if (st.ttype != 
StreamTokenizer.TT_EOF) {
                                                                if 
(st.sval.substring(0, 1).equals("|")) {
                                                                        
pendingLyric = false;
                                                                        
lyrics.add(new Lyric(pm, this, measure,
                                                                                
        words));
                                                                        words = 
new ArrayList<String>();
                                                                        if 
(st.sval.length() > 1)
                                                                                
measure = st.sval.substring(1);
                                                                        else {
                                                                                
while (st.nextToken() == StreamTokenizer.TT_EOL)
                                                                                
        ;
                                                                                
if (st.ttype != StreamTokenizer.TT_EOF) {
                                                                                
        measure = st.sval;
                                                                                
}
                                                                        }
                                                                } else {
                                                                        if 
(pendingLyric) {
                                                                                
pendingLyric = false;
                                                                                
lyrics.add(new Lyric(pm, this, measure,
                                                                                
                words));
                                                                                
words = new ArrayList<String>();
                                                                                
measure = "";
                                                                        }
                                                                        
words.add(st.sval);
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }
                } catch (IOException ioe) {
                }
                if (words.size() > 0)
                        lyrics.add(new Lyric(pm, this, measure, words));
        }
}


package lt.server;

import java.io.Serializable;
import java.util.*;

import javax.jdo.annotations.*;
import javax.jdo.*;

@PersistenceCapable(identityType = IdentityType.APPLICATION,
detachable = "true")
public class Lyric implements Serializable {
        @SuppressWarnings("unused")
        @PrimaryKey
        @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
        private com.google.appengine.api.datastore.Key key;

        @SuppressWarnings("unused")
        //@Persistent (defaultFetchGroup = "true")
        @Persistent
        private Song theSong;
        @Persistent
        public List<String> words;
        @Persistent
        public String measure;

        public Lyric(PersistenceManager pm, Song theSong, String measure,
List<String> words) {
                //pm.makePersistent(this);
                //this.theSong = theSong;
                this.measure = measure;
                this.words = words;
                //pm.makePersistent(this);
        }
}


The things that are commented out are left over from variations I have
tried in the past.  As I said I have done well over 10 hours of
experimenting.  I'm a professor of computer science and constantly
find the errors in my students' code, but I can't seem to crack this
one.
-- 
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-j...@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