Cayenne: Updating database with manually created instances of classes generated by cayenne

StackOverflow https://stackoverflow.com/questions/10946301

  •  13-06-2021
  •  | 
  •  

Question

I'm trying to use cayenne to interact with a PostgreSQL database. So far everything worked as expected but I'm now stuck with a problem I don't really understand (I'm new to cayenne).

Say I have a table "books" with usual fields (book_id, title, editor, price), a "table" authors (author_id, author_name) and a link table "books_authors" (book_id, author_id).

All the classes associated with the process of adding or editing a book share one DataContext.

I have a struts2 (I use velocity templates) form that lets you add a book and, using ajax, multiple authors associated to it. I react to certain event to fire an ajax request that calls a struts2 action that verifies if the author exists and then adds a Books_Authors object (class generated by cayenne) to the struts2 session (the action implements SessionAware).

The form looks like this:

<form action="AddOrEditBook.do">
    <input type="hidden" name="book.book_id" value="$!book.book_id" />

    <input type="text" name="book.title" value="$!book.title" />

    <input type="text" name="book.editor" value="$!book.editor" />

    <input type="number" name="book.price" value="$!book.price" />

    <input type="text" name="author" /> <input type="button" name="addAuthor" value="Add" />

    <ul>
        <li id="author_2">Author 2 <input type="button" name="removeAuthor" value="Remove" /></li>
        <li id="author_16">Author 16 <input type="button" name="removeAuthor" value="Remove" /> </li>
    </ul>

    <input type="submit" />
</form>

Once I submit the form to AddOrEditBook.do that has a setter and getter for book, struts2 creates the book object and fills it with the values of the form. That's nice.

This the thing that bothers me:

When I update a book, I didn't find a way to use the object created by struts to update the db. What I want to achieve is to somehow instruct cayenne to use the object created by struts to update the corresponding entity in the db.

I've messed a lot with things like object_id, PersistenceState, etc.:

Expression exp_book = ExpressionFactory.matchExp(Book.BOOK_ID_PROPERTY, book.getBook_id());
Book bookFromDb = RetrieveHelper.retrieveScalarByExpression(ctxt, new Book(), exp_book);

book.setObjectContext(ctxt);
book.setObjectId(bookFromDb.getObjectId());
ctxt.getObjectStore().registerNode(book.getObjectId(), book);
book.setPersistenceState(PersistenceState.MODIFIED);

What is the correct strategy when using cayenne to update db entities? Is it only possible to do that by making things like bookFromDb.setTitle(book.getTitle()); ?

Thanks!

Était-ce utile?

La solution

struts2 creates the book object and fills it with the values of the form. That's nice.

I am no Struts2 expert, but from what I am reading in the docs about form object lifecycle, such object is created by Struts2 by calling a default constructor. Unless there is a way to override this behavior, replacing it with some factory that would give you a Cayenne object from the right DataContext, what you are doing here is the right thing - you are separating the value object attached to the form (and the action class) from a persistent object.

With other frameworks like Tapestry, etc. you can bind the form to a Cayenne persistent object directly. Maybe you can extend Struts2 in a similar fashion as well??

All the classes associated with the process of adding or editing a book share one DataContext.

An unrelated piece of advise. You must have a separate DataContext for each user at the minimum (e.g. place it in HttpSession). Or if you don't keep uncommitted state between requests - maybe even one DataContext per request. In other words - do not share DataContexts unless they are read-only. Otherwise your app is not thread-safe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top