Brett,
I coded some classes based upon the mapping file as shown below, and I
got things working from start.
Here's the method I am using to create the Book and the Author instance
and to load the persisted entities:
public void testCreate() throws MappingException,
PersistenceException {
Database database = jdoManager.getDatabase();
database.begin();
Author author = new Author(1001, "Joseph", "Conrad");
Book book = new Book("1892295490", "Heart of Darkness", author);
database.create(author);
database.create(book);
// database.commit();
//
// database.begin();
Book lookup = (Book) database.load(Book.class, "1892295490");
System.out.println("Located book is named " + lookup.getTitle());
System.out.println("Authors:");
for (Iterator i = lookup.getAuthors().iterator(); i.hasNext();) {
Author bookAuthor = (Author) i.next();
System.out.println(" " + bookAuthor.getFirstName() + " "
+ bookAuthor.getLastName());
}
// database.remove(lookup);
database.commit();
database.close();
}
Please note the database.create() which is necessary to get the sample
working. I can easily send you a fully working sample as well, if you
wish so.
Please read on further down to find answers to your questions:
Regards
Werner
Brett McLaughlin wrote:
On Mar 4, 2008, at 3:39 PM, Werner Guttmann wrote:
Brett,
the sql mapping for the authors field of the class Book should read:
<sql name="author_id"
many-table="dw_books_authors"
many-key="book_isbn" />
Ok, I got this working, but troubles continue. Here's my complete
sql-mapping.xml:
<mapping>
<class name="ibm.xml.castor.Book" identity="isbn">
<map-to table="dw_books"/>
<field name="isbn" type="string">
<sql name="isbn" type="varchar" />
</field>
<field name="title" type="string">
<sql name="title" type="varchar" />
</field>
<field name="authors" type="ibm.xml.castor.Author"
collection="arraylist" required="true">
<sql name="author_id"
many-table="dw_books_authors"
many-key="book_isbn" />
</field>
</class>
<class name="ibm.xml.castor.Author" identity="id">
<map-to table="dw_authors" />
<field name="id" type="int">
<sql name="id" type="integer" />
</field>
<field name="firstName" type="string">
<sql name="first_name" type="varchar" />
</field>
<field name="lastName" type="string">
<sql name="last_name" type="varchar" />
</field>
<field name="books" type="ibm.xml.castor.Book"
collection="arraylist" required="true">
<sql name="book_isbn"
many-table="dw_books_authors"
many-key="author_id" />
</field>
</class>
</mapping>
Here's my test program:
public class SQLTester {
public static void main(String args[]) {
try {
JDOManager.loadConfiguration("jdo-conf.xml");
JDOManager jdoManager = JDOManager.createInstance("bmclaugh");
Database database = jdoManager.getDatabase();
database.begin();
Author author = new Author(1001, "Joseph", "Conrad");
Book book = new Book("1892295490", "Heart of Darkness", author);
database.create(book);
// database.create(author);
Book lookup = (Book)database.load(Book.class, "1892295490");
System.out.println("Located book is named " + lookup.getTitle());
System.out.println("Authors:");
for (Iterator i = lookup.getAuthors().iterator(); i.hasNext(); ) {
Author bookAuthor = (Author)i.next();
System.out.println(" " + bookAuthor.getFirstName() + " " +
bookAuthor.getLastName());
}
// database.remove(lookup);
database.commit();
database.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
There are several things I'm seeing that don't make sense to me:
1. No entry is ever inserted into dw_books_authors. I don't understand
why the mapping isn't taking care of this. When I do
database.create(book), isn't that enough to trigger Castor persisting
the book, the author, and the relationship between them? Additionally, I
get no entries in the authors table.
Per default, a Database.create() will persist only the entity you are
passing to the method call and NOT traverse the relationships defined in
the class mapping of the Book class. This can be changed, but I'll touch
upon this later on.
I hope this explains why you do not get any entries in the dw_authors
table, as you are NOT persisting the Author instance you created.
2. Even if I add in the database.create(author) line -- which I don't
think I should need -- this still doesn't work. In that case, an author
is inserted into the authors table, ...
Which is exactly what I'd expect, see above. But only if you uncomment
the Database.create(author) call above.
Having said that, you can use Database.setAutostore(true) *before*
startuing a transaction to configure the Database instance so that
object relations are traversed upon object insertion. In this case, you
don't have to use Database.create(author), as Castor will internally
traverse the relation from Book to Author instances.
... but there's still nothing in dw_books_authors.
Hmm, this is code. With the code I used above I get entries in all tables.
3. Despite no entries in the dw_authors or dw_books_authors, when I pull
the lookup Book from the database, it DOES have a populated Author
object with the right author name. I can't see how there's nothing in
dw_authors or dw_book_authors, yet lookup can have a correct author entry.
Well, given the fact that there's some oddity here, let me try to
explain this. You are creating both Aithor and Book instances as part of
one transaction. As per definition, those object instances will be
written to the database tables only upon commit.
But when you issue Database.create() calls, your object instances will
be added to the active transaction context (called first level cache in
Hibernate). As you longas you don't close your active transaction and
commit your changes, Database.load() operations will consult with the
transaction context (cache) before looking up things in the database.
That's the reason why you are getting fully populated object graphes
even when database write operations seem to fail. Does this make any
sense ?
Please note the commented calls to Database.commit() and
Database.create() between creating the objects and looking them up,
which I'd encourage you to use, as in a real-world scenario, object
creation and lookup normally happen on different threads/processes, and
this is how a persistence tool is designed to be used.
With the calls uncommented, you'd see that the transaction context
(cache) would be flushed to the database upon calling Database.commit(),
and the Database.load() operation(s) would work against the database
(unless you'd be using a second level cache such as ehcache, etc.)
I hope this helps.
Any ideas? I'm really pulling my hair out over this; I finally got the
underscore thing corrected, and am running into some more trouble. I
welcome any help, or any questions that I can answer to help you help me :-)
Thanks
---
Brett McLaughlin
Series Editor, Head First
O'Reilly Media, Inc.
Phone: (972) 722-6252
Fax: (972) 692-7958
E-Mail: [EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email