...
The object being edited is either persistent or transient. If it's persistent, your detachable model can look it up in the database by its primary key value. If it's transient, your detachable model needs some way to instantiate the create a new object, since the previous version was detachedbusiness object instance. By accepting a model as a constructor parameter, this becomes the responsibility of whatever page instantiates the edit page.
Here's a sketch of the a hypothetical Person edit page:
Code Block |
---|
/** @author Sam Barnum */ public class PersonEditPage { public PersonEditPage(IModel businessObject, WebPage returnPage) { setModel(new CompoundPropertyModel(businessObject)); } } public class PersonEditPage { private WebPage returnPage; /** * Create an edit page * @param businessObject Model which contains the business object to edit. * @param returnPage The page to direct the user to after a successful save operation */ public AbstractEditPagePersonEditPage(IModel businessObject, WebPage returnPage) { setModel(new CompoundPropertyModel(businessObject)); this.returnPage = returnPage; initComponents(); } void initComponents() { // create your form here } public Person getPerson() { return (Person)getModelObject(); } /** Saves the business object to the database */ void save() { EntityManager em = getEntityManager(); Person person = getPerson(); if (person.getId() == null) { // this is a transient person em.persist(person); } else { // this is a persistent person. There should be no need to call em.merge(), // because the person should be in a detachableModel which was loaded at the beginning of the request. // just in case, we'll call merge person = em.merge(person); } em.flush(); // if the person was transient, this will assign the primary key value // now we set a new Model containing the saved person setModelObject(new DetachableEntityModel(person)); // and take the user to the successful save page setResponsePage(returnPage); } /** Loads the entity manager from the session or other location */ EntityManager getEntityManager() { // implementation omitted } } |
...
Code Block |
---|
/** * Model which knows how to fetch a business object by its class and primary key value (id). * @author sbarnum */ public class DetachableEntityModel extends LoadableDetachableModel implements IModel { private final Class entityClass; private final Serializable id; /** * Create a detatchableEntityModel for a persistent object. The id of object must not be null. * @param object the business object */ public DetachableEntityModel(MyBusinessObject object) { super(object); if (object == null) throw new NullPointerException("object must not be null."); if (object.getId() == null) throw new NullPointerException("object.getId() must not be null. " + "To create a model for a transient instance, use a LoadableDetachableModel whose " + "attachload() method instantiates a new object."); this.entityClass = object.getClass(); this.id = object.getId(); } /** Loads the business object from the database */ protected MyBusinessObject load() { return ((Session)Session.get()).getEntityManagerForRequest().find(entityClass, id); } } |
If you want to edit a persistent business object (from a list page, for example), you should pass in give the PersonEditPage a DetachableEntityModel to your edit page constructorcontaining your persistent business object.
If you want to edit a newly created transient object (as a result of clicking a 'new' button, for example), you should pass in a LoadableDetachableModel whose load()
method creates and initializes a new business object. For example, suppose you have a Person
list view. You can choose a type of person to view in the listfilter the list using a dropdown menu of person type. There's a link to create a new person. You'd like to set the new person's type to match whatever is currently being displayed selected in the listdropdownlist. If the PersonEditPage were responsible for instantiating the Person object, this would get tricky. Instead, you could use the following link on your list page:
...