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


Reply via email to