--- title: Basic Use of JPAContainer order: 4 layout: page --- [[jpacontainer.usage]] = Basic Use of JPAContainer Vaadin JPAContainer offers a highly flexible API that makes things easy in simple cases while allowing extensive flexibility in demanding cases. To begin with, it is a [classname]#Container#, as described in <>. In this section, we look how to create and use [classname]#JPAContainer# instances. We assume that you have defined a domain model with JPA annotations, as described in the previous section. [[jpacontainer.usage.jpacontainerfactory]] == Creating [classname]#JPAContainer# with [classname]#JPAContainerFactory# The [classname]#JPAContainerFactory# is the easy way to create [classname]#JPAContainer#s. It provides a set of __make...()__ factory methods for most cases that you will likely meet. Each factory method uses a different type of entity provider, which are described in <>. The factory methods take the class type of the entity class as the first parameter. The second parameter is either a persistence unit name (persistence context) or an [classname]#EntityManager# instance. ---- // Create a persistent person container JPAContainer persons = JPAContainerFactory.make(Person.class, "book-examples"); // You can add entities to the container as well persons.addEntity(new Person("Marie-Louise Meilleur", 117)); // Set up sorting if the natural order is not appropriate persons.sort(new String[]{"age", "name"}, new boolean[]{false, false}); // Bind it to a component Table personTable = new Table("The Persistent People", persons); personTable.setVisibleColumns("id","name","age"); layout.addComponent(personTable); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.basic[on-line example, window="_blank"]. It's that easy. In fact, if you run the above code multiple times, you'll be annoyed by getting a new set of persons for each run - that's how persistent the container is. The basic [methodname]#make()# uses a [classname]#CachedMutableLocalEntityProvider#, which allows modifying the container and its entities, as we do above by adding new entities. When using just the persistence unit name, the factory creates an instance of [classname]#EntityManagerFactory# for the persistence unit and uses it to build entity managers. You can also create the entity managers yourself, as described later. The entity providers associated with the different factory methods are as follows: [[table.jpacontainer.usage.jpacontainerfactory]] .[classname]#JPAContainerFactory# Methods |=============== |[methodname]#make()#|[classname]#CachingMutableLocalEntityProvider# |[methodname]#makeReadOnly()#|[classname]#CachingLocalEntityProvider# |[methodname]#makeBatchable()#|[classname]#BatchableLocalEntityProvider# |[methodname]#makeNonCached()#|[classname]#MutableLocalEntityProvider# |[methodname]#makeNonCachedReadOnly()#|[classname]#LocalEntityProvider# |=============== [classname]#JPAContainerFactory# holds a cache of entity manager factories for the different persistence units, making sure that any entity manager factory is created only once, as it is a heavy operation. You can access the cache to get a new entity manager with the [methodname]#createEntityManagerForPersistenceUnit()# method. ---- // Get an entity manager EntityManager em = JPAContainerFactory. createEntityManagerForPersistenceUnit("book-examples"); // Do a query em.getTransaction().begin(); em.createQuery("DELETE FROM Person p").executeUpdate(); em.persist(new Person("Jeanne Calment", 122)); em.persist(new Person("Sarah Knauss", 119)); em.persist(new Person("Lucy Hannah", 117)); em.getTransaction().commit(); ... ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.basic[on-line example, window="_blank"]. Notice that if you use update the persistent data with an entity manager outside a [classname]#JPAContainer# bound to the data, you need to refresh the container as described in <>. [[jpacontainer.usage.jpacontainerfactory.thehardway]] === Creating [classname]#JPAContainer# Manually While it is normally easiest to use a [classname]#JPAContainerFactory# to create [classname]#JPAContainer# instances, you may need to create them manually. It is necessary, for example, when you need to use a custom entity provider or extend [classname]#JPAContainer#. First, we need to create an entity manager and then the entity provider, which we bind to a [classname]#JPAContainer#. ---- // We need a factory to create entity manager EntityManagerFactory emf = Persistence.createEntityManagerFactory("book-examples"); // We need an entity manager to create entity provider EntityManager em = emf.createEntityManager(); // We need an entity provider to create a container CachingMutableLocalEntityProvider entityProvider = new CachingMutableLocalEntityProvider(Person.class, em); // And there we have it JPAContainer persons = new JPAContainer (Person.class); persons.setEntityProvider(entityProvider); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.thehardway[on-line example, window="_blank"]. You could save the first step by asking the entity manager from the [classname]#JPAContainerFactory#. [[jpacontainer.usage.entitites]] == Creating and Accessing Entities JPAContainer integrates with the JPA entity manager, which you would normally use to create and access entities with JPA. You can use the entity manager for any purposes you may have, and then [classname]#JPAContainer# to bind entities to user interface components such as [classname]#Table#, [classname]#Tree#, any selection components, or a [classname]#Form#. You can add new entities to a [classname]#JPAContainer# with the [methodname]#addEntity()# method. It returns the item ID of the new entity. ---- Country france = new Country("France"); Object itemId = countries.addEntity(france); ---- The item ID used by [classname]#JPAContainer# is the value of the ID property (column) defined with the [literal]#++@Id++# annotation. In our [classname]#Country# entity, it would have [classname]#Long# type. It is generated by the entity manager when the entity is persisted and set with the setter for the ID proeprty. Notice that the [methodname]#addEntity()# method does __not__ attach the entity instance given as the parameter. Instead, it creates a new instance. If you need to use the entity for some purpose, you need to get the actual managed entity from the container. You can get it with the item ID returned by [methodname]#addEntity()#. ---- // Create a new entity and add it to a container Country france = new Country("France"); Object itemId = countries.addEntity(france); // Get the managed entity france = countries.getItem(itemId).getEntity(); // Use the managed entity in entity references persons.addEntity(new Person("Jeanne Calment", 122, france)); ---- [[jpacontainer.usage.entitites.items]] === Entity Items The [methodname]#getItem()# method is defined in the normal Vaadin [interfacename]#Container# interface. It returns an [classname]#EntityItem#, which is a wrapper over the actual entity object. You can get the entity object with [methodname]#getEntity()#. An [classname]#EntityItem# can have a number of states: persistent, modified, dirty, and deleted. The dirty and deleted states are meaningful when using __container buffering__, while the modified state is meaningful when using __item buffering__. Both levels of buffering can be used together - user input is first written to the item buffer, then to the entity instance, and finally to the database. The [methodname]#isPersistent()# method tells if the item is actually persistent, that is, fetched from a persistent storage, or if it is just a transient entity created and buffered by the container. The [methodname]#isModified()# method checks whether the [classname]#EntityItem# has changes that are not yet committed to the entity instance. It is only relevant if the item buffering is enabled with [methodname]#setBuffered(true)# for the item. The [methodname]#isDirty()# method checks whether the entity object has been modified after it was fetched from the entity provider. The dirty state is possible only when buffering is enabled for the container. The [methodname]#isDeleted()# method checks whether the item has been marked for deletion with [methodname]#removeItem()# in a buffered container. [[jpacontainer.usage.entitites.refreshing]] === Refreshing JPAContainer In cases where you change [classname]#JPAContainer# items outside the container, for example by through an [interfacename]#EntityManager#, or when they change in the database, you need to refresh the container. The [interfacename]#EntityContainer# interface implemented by [classname]#JPAContainer# provides two methods to refresh a container. The [methodname]#refresh()# discards all container caches and buffers and refreshes all loaded items in the container. All changes made to items provided by the container are discarded. The [methodname]#refreshItem()# refreshes a single item. [[jpacontainer.usage.nested-properties]] == Nested Properties If you have a one-to-one or many-to-one relationship, you can define the properties of the referenced entity as __nested__ in a [classname]#JPAContainer#. This way, you can access the properties directly through the container of the first entity type as if they were its properties. The interface is the same as with [classname]#BeanContainer# described in <>. You just need to add each nested property with [methodname]#addNestedContainerProperty()# using dot-separated path to the property. ---- // Have a persistent container JPAContainer persons = JPAContainerFactory.make(Person.class, "book-examples"); // Add a nested property to a many-to-one property persons.addNestedContainerProperty("country.name"); // Show the persons in a table, except the "country" column, // which is an object - show the nested property instead Table personTable = new Table("The Persistent People", persons); personTable.setVisibleColumns("name", "age", "country.name"); // Have a nicer caption for the country.name column personTable.setColumnHeader("country.name", "Nationality"); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.nested[on-line example, window="_blank"]. The result is shown in <>. Notice that the [literal]#++country++# property in the container remains after adding the nested property, so we had to make that column invisible. Alternatively, we could have redefined the [methodname]#toString()# method in the country object to show the name instead of an object reference. [[figure.jpacontainer.usage.nested-properties]] .Nested Properties image::img/nested-properties.png[] You can use the [literal]#++*++# wildcard to add all properties in a nested item, for example, " [literal]#++country.*++#". [[jpacontainer.usage.hierarchical]] == Hierarchical Container [classname]#JPAContainer# implements the [interfacename]#Container.Hierarchical# interface and can be bound to hierarchical components such as a [classname]#Tree# or [classname]#TreeTable#. The feature requires that the hierarchy is represented with a __parent__ property that refers to the parent item. At database level, this would be a column with IDs. The representation would be as follows: ---- @Entity public class CelestialBody implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @ManyToOne private CelestialBody parent; ... } ... // Create some entities CelestialBody sun = new CelestialBody("The Sun", null); CelestialBody mercury = new CelestialBody("Mercury", sun); CelestialBody venus = new CelestialBody("Venus", sun); CelestialBody earth = new CelestialBody("Earth", sun); CelestialBody moon = new CelestialBody("The Moon", earth); CelestialBody mars = new CelestialBody("Mars", sun); ... ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.hierarchical[on-line example, window="_blank"]. You set up a [classname]#JPAContainer# to have hierarchy by calling [methodname]#setParentProperty()# with the name of the property that refers to the parent. Coincidentally, it is named " [literal]#++parent++#" in the example: ---- // Create the container JPAContainer bodies = JPAContainerFactory.make(CelestialBody.class, "my-unit"); // Set it up for hierarchical representation bodies.setParentProperty("parent"); // Bind it to a hierarhical component Tree tree = new Tree("Celestial Bodies", bodies); tree.setItemCaptionMode(Tree.ITEM_CAPTION_MODE_PROPERTY); tree.setItemCaptionPropertyId("name"); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.hierarchical[on-line example, window="_blank"]. You can use the [methodname]#rootItemIds()# to acquire the item IDs of the root elements with no parent. ---- // Expand the tree for (Object rootId: bodies.rootItemIds()) tree.expandItemsRecursively(rootId); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.hierarchical[on-line example, window="_blank"]. [[jpacontainer.usage.hierarchical.unsupported]] === Unsupported Hierarchical Features Using [methodname]#setParent()# in the container to define parenthood is not supported. Also, the current implementation does not support __setChildrenAllowed()__, which controls whether the user can expand a node by clicking a toggle. The toggle is by default visible for all nodes, even if they have no children. The method is not supported because it would require storing the information outside the entities. You can override [methodname]#areChildrenAllowed()# to implement the functionality using a custom logic. ---- // Customize JPAContainer to define the logic for // displaying the node expansion indicator JPAContainer bodies = new JPAContainer(CelestialBody.class) { @Override public boolean areChildrenAllowed(Object itemId) { // Some simple logic return getChildren(itemId).size() > 0; } }; bodies.setEntityProvider( new CachingLocalEntityProvider( CelestialBody.class, em)); ---- See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.hierarchical[on-line example, window="_blank"].