diff options
Diffstat (limited to 'documentation/jpacontainer/jpacontainer-usage.asciidoc')
-rw-r--r-- | documentation/jpacontainer/jpacontainer-usage.asciidoc | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/documentation/jpacontainer/jpacontainer-usage.asciidoc b/documentation/jpacontainer/jpacontainer-usage.asciidoc new file mode 100644 index 0000000000..c4ba3b2a3f --- /dev/null +++ b/documentation/jpacontainer/jpacontainer-usage.asciidoc @@ -0,0 +1,386 @@ +--- +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 +<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container,"Collecting +Items in Containers">>. + +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 +<<dummy/../../../framework/jpacontainer/jpacontainer-entityprovider#jpacontainer.entityprovider,"Entity +Providers">>. + +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<Person> 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.entitites>>. + +[[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<Person> entityProvider = + new CachingMutableLocalEntityProvider<Person>(Person.class, + em); + +// And there we have it +JPAContainer<Person> persons = + new JPAContainer<Person> (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 +<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container.beancontainer,"BeanContainer">>. +You just need to add each nested property with +[methodname]#addNestedContainerProperty()# using dot-separated path to the +property. + + +---- +// Have a persistent container +JPAContainer<Person> 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 <<figure.jpacontainer.usage.nested-properties>>. 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<CelestialBody> 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<CelestialBody> bodies = + new JPAContainer<CelestialBody>(CelestialBody.class) { + @Override + public boolean areChildrenAllowed(Object itemId) { + // Some simple logic + return getChildren(itemId).size() > 0; + } +}; +bodies.setEntityProvider( + new CachingLocalEntityProvider<CelestialBody>( + CelestialBody.class, em)); +---- +See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.hierarchical[on-line example, window="_blank"]. + + + + + |