Jump to: navigation, search

Teneo/Hibernate/Tutorial

< Teneo‎ | Hibernate
Revision as of 02:02, 29 November 2012 by Mtaal.elver.org (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This tutorial shows how EMF, Teneo and Hibernate work together to automatically create the database schema and persist EMF objects. The tutorial also shows examples of HQL queries for EMF object and using the EMF Hibernate resource.

This tutorial uses the example project which you can download here.

This tutorial assumes some basic knowledge of EMF. If you are new to EMF then it can make sense to first try one of the core EMF tutorials which you can find here.

Initial Setup

The tutorial assumes that you have a running Eclipse with EMF and Teneo installed. In addition the Teneo dependencies (incl. hsqldb and mysql drivers) should be installed. See the Download & Install page for more information.

This tutorial uses hsqldb but it can easily be changed to use mysql or another database. For other databases than hsqldb and mysql you need to take make sure that the jdbc driver is in the classpath of the org.eclipse.emf.teneo.hibernate.examples project.

For mysql and other non-in-memory databases you have to create the database up-front (so not the tables inside the database but just the database itself). For this tutorial the database name should be: library.

Running the tutorial

After downloading the examples project from cvs you can directly run the tutorial. Open the project and navigate to the Tutorial.java file and right click and select 'Run As > Java Application'. You will see several things getting printed to the console (one of them is the generated Hibernate mapping).

This run takes the following steps:

  • reads the EPackage model from the generated EPackage file.
  • generate a hibernate mapping for the EPackage
  • create the database (on hsqldb)
  • create objects and persist them
  • read the objects back using queries
  • make changes, add new objects and persist them
  • read and update the objects an EMF Hibernate resource

Walk-Through

The tutorial java class executes several steps. The initialization part calls Teneo directly, in the remaining runtime steps only EMF and Hibernate are directly used.

Initialization

The initialization starts by setting both Hibernate as well as Teneo properties in a properties map:

// To configure Hibernate, supply properties describing the JDBC driver,
// URL, username/password and SQL dialect.
// By default the properties are obtained from the file
// "hibernate.properties" at the classpath root.
//
// Alternatively, you can set the properties programmatically:
// 
// For more information see <a
// href="http://www.hibernate.org/hib_docs/v3/reference/en/html/session-configuration.html#configuration-programmatic">
// section 3.1 of the Hibernate manual</a>.
//
Properties hibernateProperties = new Properties();
 
//
// 1) From a ".properties" file or stream.
// InputStream in = ...
// hibernateProperties.load(in);
//
// 2) or populated manually:
//		hibernateProperties.setProperty(Environment.DRIVER, "com.mysql.jdbc.Driver");
//		hibernateProperties.setProperty(Environment.USER, "root");
//		hibernateProperties.setProperty(Environment.URL, "jdbc:mysql://127.0.0.1:3306/library");
//		hibernateProperties.setProperty(Environment.PASS, "root");
//		hibernateProperties.setProperty(Environment.DIALECT, "org.hibernate.dialect.MySQL5InnoDBDialect");
 
hibernateProperties.setProperty(Environment.DRIVER, "org.hsqldb.jdbcDriver");
hibernateProperties.setProperty(Environment.USER, "sa");
hibernateProperties.setProperty(Environment.URL, "jdbc:hsqldb:file:/tmp/hsqldb");
hibernateProperties.setProperty(Environment.PASS, "");
hibernateProperties.setProperty(Environment.DIALECT, org.hibernate.dialect.HSQLDialect.class.getName());

Teneo has many configuration options, these are set as follows:

// set a specific option
// see this page http://wiki.eclipse.org/Teneo/Hibernate/Configuration_Options
// for all the available options
hibernateProperties.setProperty(PersistenceOptions.CASCADE_POLICY_ON_NON_CONTAINMENT, "REFRESH,PERSIST,MERGE");
 
// use the joined inheritance mapping
hibernateProperties.setProperty(PersistenceOptions.INHERITANCE_MAPPING, "JOINED");
 
// use an annotations file as an example
// this lets the library use a special table 
hibernateProperties.setProperty(PersistenceOptions.PERSISTENCE_XML,
	"org/eclipse/emf/teneo/hibernate/examples/annotations.xml");

Then a datastore is created. The datastore manages the persistence of one or more EPackages. It takes care of generating the model-relational mapping and initialization of Hibernate. The last step of the initialization is creating the session factory. The session factory is used at runtime in the next steps.

// Create the DataStore.
final String dataStoreName = "LibraryDataStore";
final HbDataStore dataStore = HbHelper.INSTANCE.createRegisterDataStore(dataStoreName);
dataStore.setDataStoreProperties(hibernateProperties);
 
// Configure the EPackages used by this DataStore.
dataStore.setEPackages(new EPackage[] { ExtlibraryPackage.eINSTANCE });
 
// Initialize the DataStore. This sets up the Hibernate mapping and, in
// turn, creates the corresponding tables in the database.
try {
	dataStore.initialize();
} finally {
			// print the hibernate mapping
	System.err.println(dataStore.getMappingXML());
}
 
final SessionFactory sessionFactory = dataStore.getSessionFactory();

Persisting EMF Objects

The next step creates a number of EMF objects and persists them:

// Open a new Session and start transaction.
final Session session = sessionFactory.openSession();
session.beginTransaction();
 
// Create a library.
Library library = ExtlibraryFactory.eINSTANCE.createLibrary();
library.setName("My Library");
// Make it persistent.
session.save(library);
 
// Create a writer and book...
... code truncated ...
 
// Commit the changes to the database.
session.getTransaction().commit();
// Close the session. Not necessary if
session.close();

As you can see, Teneo is not used explicitly at runtime, it is only standard EMF and Hibernate. The above code created and persisted a Library with a Book and a Writer. In the next step these are queries again.

Reading EMF Objects using HQL queries

As a next step the data is queried using HQL. The example show that you need to use model names in the HQL queries and not the java implementation names (this is also why Teneo supports Dynamic EMF out-of-the-box).

The code snippets below show some examples, for the full code check the Tutorial.java file in the examples project.

First create a session and start a transaction:

final Session session = sessionFactory.openSession();
session.beginTransaction();

Now do some queries, first for all books:

// Retrieve all Books and display their titles.
Query query = session.createQuery("FROM Book");
List<?> books = query.list();
for (Iterator<?> it = books.iterator(); it.hasNext();) {
	Book book = (Book) it.next();
	System.out.println(book.getTitle());
}

Or query for a specific Book:

// Retrieve George Orwell's book.
query = session.createQuery("SELECT book FROM Book book, Writer writ WHERE "
		+ " book.title='1984' AND book.author=writ AND writ.name='G. Orwell'");
books = query.list();

Hibernate also supports functions in the select clause (and many more things):

// Count the number of books in the library
query = session.createQuery("SELECT count(allbooks) FROM Library lib LEFT JOIN lib.books AS allbooks "
		+ " WHERE lib.name='My Library'");
int count = ((Number) query.uniqueResult()).intValue();

Using the EMF Hibernate Resource

Teneo provides a Hibernate EMF resource implementation which integrates the EMF resource with Hibernate. The tutorial class shows an example of using a Hibernate resource.

The hibernate resource has an URI starting with the hibernate protocol:

String uriStr = "hibernate://?" + HibernateResource.DS_NAME_PARAM + "=" + dataStoreName;
final URI uri = URI.createURI(uriStr);
ResourceSet resourceSet = new ResourceSetImpl();
final Resource res = resourceSet.createResource(uri);

Loading the resource will load the root objects into the resource. Contained objects are normally lazy loaded on first access:

res.load(Collections.EMPTY_MAP);
Iterator<?> it = res.getContents().iterator();
Library libTest;
while (it.hasNext()) {
	libTest = (Library) it.next();
	System.out.println(libTest.getName());
}

Create some new objects and add them to the resource:

Library libNew = ExtlibraryFactory.eINSTANCE.createLibrary();
libNew.setName("My Second Library");
 
// create a writer
Writer writerNew = ExtlibraryFactory.eINSTANCE.createWriter();
writerNew.setName("I. Asimov");
writerNew.setFirstName("Isaac");
writerNew.setLastName("Asimov");
 
// and one of his books
Book bookNew = ExtlibraryFactory.eINSTANCE.createBook();
bookNew.setAuthor(writerNew);
bookNew.setPages(305);
bookNew.setTitle("Foundation and Empire");
bookNew.setCategory(BookCategory.SCIENCE_FICTION);
 
// add the writer/book to the library.
libNew.getWriters().add(writerNew);
libNew.getBooks().add(bookNew);
 
// now add the top-level object to the resource
res.getContents().add(libNew);

And as a last step save the resource, this will flush the new/changed/removed objects to the database:

res.save(null);