slide 1 application design ee557: server-side development

75
Slide 1 Application Design EE557: Server-Side Development

Post on 19-Dec-2015

218 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Slide 1 Application Design EE557: Server-Side Development

Slide 1

Application Design

EE557: Server-Side Development

Page 2: Slide 1 Application Design EE557: Server-Side Development

Slide 2

Model 1 Architecture

EE557: Server-Side Development

Page 3: Slide 1 Application Design EE557: Server-Side Development

Slide 3

Model 1 Architecture Problems

EE557: Server-Side Development

• Duplication of functionality in servlets/JSPs

• Ties business logic and presentation logic together!

• Difficult to create a new view (eg. WML interface)

• Internationalisation

• Any of these familiar?

Page 4: Slide 1 Application Design EE557: Server-Side Development

Slide 4

Model 2 Architecture

EE557: Server-Side Development

• ‘Controller’ receives all requests for the application. • It processes the request and interacts with the ‘Model’• Prepares data to present to the ‘View’. Response to user is presented in the ‘View’ • ‘View’ typically JSPs

Page 5: Slide 1 Application Design EE557: Server-Side Development

Slide 5

Model 2 Architecture

EE557: Server-Side Development

• MVC is a design pattern - a blueprint for constructing a time-tested solution to a given problem

• It is not an implementation

• Three layers of functionality:- Model Components: The data and business logic- View Components: Presentation- Controller Components: The flow control

Page 6: Slide 1 Application Design EE557: Server-Side Development

Slide 6

Model Components

EE557: Server-Side Development

• Provide access to our business data and logic to manipulate data

• Typically interacts with a persistent storage mechanism (DBMS)

• Controller components typically don’t embed code for manipulating data -> instead they communicate with the Model which performs data access and manipulation

• Model components can be implemented as JavaBeans, Enterprise JavaBeans (EJBs) and a range of other options

Page 7: Slide 1 Application Design EE557: Server-Side Development

Slide 7

EE557: Server-Side Development

View Components

• Responsible for displaying data from the Model to the user

• Typically simple JSPs or HTML pages

• Seperation of business and presentation logic, allows other view technologies such as WML

• Open to future presentation technologies

Page 8: Slide 1 Application Design EE557: Server-Side Development

Slide 8

Controller Components

EE557: Server-Side Development

• Core part of MVC Architecture

• Handle all requests from the user and selects the View to return

• Typically a servlet, which manages the flow of data between the Model and the View

• When Controller receives a request it forwards the details to an appropriate Handler, which determines what action to take

• The handler might call on the Model to perform a specific function After the Controller selects the View to send back to the user based on the state of the Model’s data

Page 9: Slide 1 Application Design EE557: Server-Side Development

Slide 9

EE557: Server-Side Development

Internationalisation (i18n) &Localisation (l10n)

• The means of adapting computer software to different languages and regional differences

• Acrynoms based on counting letters between first and last letter

• Creating multiple versions of applications is NOT a viable option - updating becomes a nightmare

• Internationalisation is the process of designing an application so that it can adapt to various languages and regions WITHOUT engineering changes!

• Localisation is the process of adapting internationalised software for a specific region or language by adding locale-specific components and translating text.

Page 10: Slide 1 Application Design EE557: Server-Side Development

Slide 10

EE557: Server-Side Development

Internationalisation (i18n) &Localisation (l10n)

• Internationalisation and localisation handled in most situations by the abstraction of language away from underlying code

• Most MVC frameworks will provide functionality for doing so

• Example Struts: - ApplicationResources.properties- ApplicationResources_fr.properties- ApplicationResources_de.properties

etc.

• When browsers make requests, they pass along a HTTP header (Accept-Language) that indicates the user’s Locale (country, language etc.)

Page 11: Slide 1 Application Design EE557: Server-Side Development

Slide 11

ApplicationResources.properties

EE557: Server-Side Development

#errors associated with the Login page error.username.required=username is required. error.password.required=password is required. error.login.invalid=Login Failure: The DCU Novell username/password ….

#login page text login.title=Welcome to EE557 - Please Login login.message=Enter your username and password: login.username=Username: login.password=Password: login.button.commit=Login login.help.message=Login Help

#loggedin page text loggedin.title=Login Project loggedin.msg=Welcome, {0}. You are now logged in.

Page 12: Slide 1 Application Design EE557: Server-Side Development

Slide 12

Object-Relational Persistence

EE557: Server-Side Development

• Majority of Applications require persistent data, typically in a DBMS

• Relational DBMS are designed to be understandable in a human way

• Java Applications are written with an object-oriented approach

• Relational tables in rows and columns vs objects with attributes and associations

There is an overhead in moving from objects -> relational data and from relational data -> objects

• This programming overhead is known as the object-relational gap

Let’s look at some code!

Page 13: Slide 1 Application Design EE557: Server-Side Development

Slide 13

Object-Relational Persistence

EE557: Server-Side Development

public class Customer { private Long ID; private String surname; private String firstname; private String email;

// Constructor public Customer(Long ID, String surname, String firstname, String email) {

this.ID = ID;this.surname = surname; this.firstname = firstname; this.email = email;

}

// Now the get methods public Long getID() { return ID; } public String getName() { return firstname + " " + surname; } public String getSurname() { return surname; } public String getFirstname() { return firstname; } public String getEmail() { return email; }

// And some set methods public void setID(Long value) { ID = value; } public void setSurname(String value) { surname = value; } public void setFirstname(String value) { firstname = value; } public void setEmail(String value) { email = value; }

}

Page 14: Slide 1 Application Design EE557: Server-Side Development

Slide 14

Object-Relational Persistence

EE557: Server-Side Development

• We can manually perform something like the following

public boolean addCustomer(Customer customer) { // JDBC Connection and statement setup..... PreparedStatement pstmt = con.prepareStatement("INSERT INTO CUSTOMERS

(ID,SURNAME,FIRSTNAME,EMAIL) VALUES (?,?,?,?)"); pstmt.clearParameters(); pstmt.setString(1, customer.getID());pstmt.setString(2, customer.getFirstname());pstmt.setString(3, customer.getSurname()); pstmt.setString(4, customer.getEmail()); pstmt.executeUpdate(); // handle closing down of connections etc.

}

• Rather simply we just map each field of the object to one column in a database table called CUSTOMERS

• This works correctly!

Page 15: Slide 1 Application Design EE557: Server-Side Development

Slide 15

Object-Relational Persistence

EE557: Server-Side Development

• However, what happens with our objects have many separate multi-dimensional fields and nested relationships?

• Consider if we wanted to add a Vector of billing addresses to our Customer object

... private String email; private Vector billingAddresses; ....

public Vector getBillingAddresses() { return billingAddresses; } public void setBillingAddresses(Vector value) { billingAddresses = value; } ....

• So how do we handle this two dimensional array of addresses? - Create a nested table in the DBMS (if supported) ? - Create a separate table CUSTOMERADDRESSES + FK/PK relationship

• How to handle relationships with other object tpes… Eg. Customers with Orders

• As the data structures become more complicated so do our DBMS structures and persistence code

Page 16: Slide 1 Application Design EE557: Server-Side Development

Slide 16

Object-Relational Persistence

EE557: Server-Side Development

• Estimated by some, that 35% of application code is spent on these conversions

• Look at some options!

Hand-Coding• There are design patterns which help handwrite the JDBC code to interact with databases.

• However, the work involved is often considerable as we have discussed

Serialization• As we have seen, serialization provides the ability to write objects to a byte-stream

• We can then persist this byte-stream in a database

• Not suitable for searches or arbitrary data retrieval. Eg. to change an email address of a customer you would need to deserialise, change the object and serialise again

Page 17: Slide 1 Application Design EE557: Server-Side Development

Slide 17

Object-Relational Persistence

EE557: Server-Side Development

Entity Beans (EJBs)

• Very popular approach for persisting object data

• BMP (Bean Managed Persistence) requires handcoded JDBC, with associated problems

• CMP (Container Managed Persistence) Beans let the container handle persistence with the database

• CMP mapping configuration difficult, discrepancies between application servers and varying capabilities many developers looking for alternative solutions

Page 18: Slide 1 Application Design EE557: Server-Side Development

Slide 18

Object-Relational Persistence

EE557: Server-Side Development

Object-Oriented Database Systems

• In the mid-90s object-oriented database management systems (OODBMS) gained attention

• OODBMS offer seamless integration into the object-oriented application environment

• OODBMS have not had much uptake and are not a popular solution

• RDBMS still contain the vast majority of the market share

Page 19: Slide 1 Application Design EE557: Server-Side Development

Slide 19

Object-Relational Persistence

EE557: Server-Side Development

Object/Relational Mapping (ORM)

• ORM is the automated persistence of objects in a Java application to tables in a relational database

• This is achieved through configuration, where you define the way you map your classes to tables once (which property to which column, which class to which table etc.)

• Now we can: orm.save(myCustomer); or myCustomer = orm.load(Customer.class, customerID);

• ORM implementations are complex and not recommended for small projects due to their steep learning curve. However they have considerable advantages.

Page 20: Slide 1 Application Design EE557: Server-Side Development

Slide 20

Object-Relational Persistence

EE557: Server-Side Development

Object/Relational Mapping (ORM)

Advantages

• Productivity – Eliminates much of the grunt work for developers

• Maintainability – Few lines of developer code, modifications to data structure only require changes to the ORM configuration (rather than code + SQL)

• Performance – ORM is known for its database efficiency

• Vendor Independence – ORMs abstract your application away from underlying SQL databases, SQL dialects and reliance on application servers (like with EJBs)

Page 21: Slide 1 Application Design EE557: Server-Side Development

Slide 21

Object-Relational Persistence

EE557: Server-Side Development

Hibernate

• Hibernate is the most mature and complete open-source, object relational mapper

• Developed by a team of Java software developers from around the world

• It can significantly reduce development time on large-scale projects

Has experienced considerable growth in popularity in recent years

How does it work?

Page 22: Slide 1 Application Design EE557: Server-Side Development

Slide 22

Hibernate

EE557: Server-Side Development

package edu.ee.beans;

public class Customer { private int id; private String username; private String password; private String firstname; private String surname; private String email;

public Customer(int id, String username, String password, String firstname, String surname, String email) {

super(); this.id = id; this.username = username; this.password = password; this.firstname = firstname; this.surname = surname; this.email = email;

}

public Customer() { }

public int getId() { return id; } public void setId(int id) { this.id = id; }

Page 23: Slide 1 Application Design EE557: Server-Side Development

Slide 23

public String getUsername() { return username; }

public void setUsername(String username) { this.username = username; }

public String getPassword() { return password; }

public void setPassword(String password) { this.password = password; }

public String getFirstname() { return firstname; }

public void setFirstname(String firstname) { this.firstname = firstname; }

public String getSurname() { return surname; }

public void setSurname(String surname) { this.surname = surname; }

public String getEmail() { return email; }

public void setEmail(String email) { this.email = email; } }

EE557: Server-Side Development

Hibernate

Page 24: Slide 1 Application Design EE557: Server-Side Development

Slide 24

Hibernate

EE557: Server-Side Development

Hibernate code to create a new Customer:

Customer customer = new Customer(); customer.setUsername("smithj"); customer.setPassword("mypass"); customer.setFirstname("John"); customer.setSurname("Smith"); customer.setEmail("[email protected]");

Session hibernateSession = HibernateUtil.getSession(); hibernateSession.save(customer);

•OK – so there’s a little more to it than this!

Page 25: Slide 1 Application Design EE557: Server-Side Development

Slide 25

Hibernate

EE557: Server-Side Development

• Where is the SQL? There isn’t any!

• Behind the scenes: Hibernate will use some mapping information to generate appropriate SQL for the underlying database, such as:

insert into CUSTOMERS (ID, USERNAME, PASSWORD, FIRSTNAME,SURNAME, EMAIL) values (1, ‘smithj’, ‘mypass’, ‘John’, ‘Smith’, ‘[email protected]’);

• Most of the work in Hibernate is on developing these mappings - Configuration of which database/details we will be using - Configuration of the mappings for CRUD operations on our classes

• Developers still need to understand SQL for a range of reasons

• In particular, even for Hibernate we still need a strong understand of primary and foreign key relationships and data integrity

Page 26: Slide 1 Application Design EE557: Server-Side Development

Slide 26

EE557: Server-Side Development

Hibernate

• Previous technique for performing mappings

<hibernate-mapping> <class name=”edu.ee.beans.Customer table=”Customer”>

<id name=”id” column=”id”> <generator class=”native”/>

</id> <property name=”username” column=”username”> <property name=”password” column=”password”> <property name=”firstname” column=”firstname”> <property name=”surname” column=”surname”> <property name=”email” column=”email”>

</class> </hibernate-mapping>

Page 27: Slide 1 Application Design EE557: Server-Side Development

Slide 27

EE557: Server-Side Development

Hibernate

• New technique using Java Annotations, introduced in Java 1.5

• Removes reliance on awkward XML configuration files (apart from one)

• Rather than having a separate configuration file, we “annotate” our JavaBeans directly putting the mapping information into the beans

Page 28: Slide 1 Application Design EE557: Server-Side Development

Slide 28

Annotated Beanpackage edu.ee.beans; import javax.persistance.*;

@Entitypublic class Customer {

private int id; private String username; private String password; private String firstname; private String surname; private String email;

public Customer(int id, String username, String password, String firstname, String surname, String email) {

super(); this.id = id; this.username = username; this.password = password; this.firstname = firstname; this.surname = surname; this.email = email;

} public Customer() { }

@Id@GeneratedValuepublic int getId() { return id; } public void setId(int id) { this.id = id; } …..

….. other getter and setter methods as before…..

Page 29: Slide 1 Application Design EE557: Server-Side Development

Slide 29

EE557: Server-Side Development

Hibernate

• @Entity - tells Hibernate that it will be responsible for handing the database operations for this bean

• @Id - identifies the primary key

• @GeneratedValue - indicates that the primary key will be automatically generated

• By default, all of the remaining fields are mapped to columns of the same name (hence, few annotations in this example – can be overridden)

Page 30: Slide 1 Application Design EE557: Server-Side Development

Slide 30

EE557: Server-Side Development

Handwritten JDBC vs Hibernate

• Hibernate takes time to learn – temptation to just continue writing JDBC/SQL

Want to change to a different database system (RDBMS) which has a considerably different implementation of SQL?  Hand-written JDBC Code: Big problem!  Rewrite of most embedded SQL.Hibernate: No problem! Change three lines in a Hibernate configuration file! 

Fed up manually creating table structures using the ‘CREATE TABLE’ statement?  Hand-written JDBC Code: Keep doing it (or use a UI)Hibernate: ONE line of code can be used to create ALL of your tables automatically, in whichever database dialect you have configured.

Tired of constantly getting database errors because you are moving between Java objects and relational database tables? Hand-written JDBC Code: No other optionHibernate: work with objects 100% of the time and never write SQL manually again!

Page 31: Slide 1 Application Design EE557: Server-Side Development

Slide 31

EE557: Server-Side Development

Hibernate – Getting Started

What do we need?

1. A JDBC compliant database: Hibernate will work with all popular databases.  (Already have this!)

2. JDK 5.0 or better: as annotations didn’t exist before Java 5. (Already have this!)

3. JDBC Drivers for your database: the JDBC drivers are used by Hibernate to connect to the database.  (Already have this!)

4. Eclipse: our development environment (Already have this!)5. Hibernate: we require the various JAR files and libraries which form

Hibernate. (New!)6. A hibernate.cfg.xml file on your classpath (New!)

Page 32: Slide 1 Application Design EE557: Server-Side Development

Slide 32

EE557: Server-Side Development

Hibernate – Getting Started

5. Hibernate JAR Files and Libraries

• To use Hibernate we require a number of JAR files, containing both Hibernate and Hibernate Annotations support.

• Up until Hibernate Version 3.4 Hibernate Core and Annotations libraries Were separate downloads

• Version 3.5.x onwards Hibernate Annotations is bunded with Core

• There are additionally a number of support libraries that Hibernate uses, which we must also include – these are also bundled

• We actually include about a dozen individual JAR files in our Hibernate applications (import into WEB-INF/lib and set up build paths)

Page 33: Slide 1 Application Design EE557: Server-Side Development

Slide 33

EE557: Server-Side Development

Hibernate – Getting Started

6. A Working hibernate.cfg.xml fileSpecial configuration file that tells Hibernate

• where our database is

• what database driver to use to connect to the database

• what type of database “dialect” to use

• what the connection URL is

• what the database username and password are

• other configurations…

Page 34: Slide 1 Application Design EE557: Server-Side Development

Slide 34

EE557: Server-Side Development

Hibernate<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="connection.url">jdbc:oracle:thin:@136.206.35.131:1521:SSD</property> <property name="connection.username">ee_user</property> <property name="connection.password">ee_pass</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">0</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> <!-- Enable Hibernate's current session context --> <property name="current_session_context_class">thread</property> <!-- Echo all executed SQL to stdout --> <property name="hibernate.show_sql">true</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> </session-factory> </hibernate-configuration>

Do not try to learn off these configuration files!

Page 35: Slide 1 Application Design EE557: Server-Side Development

Slide 35

EE557: Server-Side Development

HibernateUtil.java

• Not listed in Steps 1-6 as it is an additional optional step for our setup

• Support helper class we will use to directly interact with Hibernate

• Provides a number of methods which make interacting with Hibernate easier and with fewer lines of code

• Open HibernateUtil in Eclipse

• Number of methods in HibernateUtil

Page 36: Slide 1 Application Design EE557: Server-Side Development

Slide 36

EE557: Server-Side Development

HibernateUtil.java (don’t learn this off!)

• getInitializedConfiguration(): Configures and AnnotationConfiguration object. This is where we tell Hibernate to manage responsibility for database operations for our beans. Simply annotating beans is not enough!

• recreateDatabase() – once the AnnotationConfiguration object has been configured, Hibernate can automatically generated the SQL required to automatically create all of the applicable tables Note: We need to be careful with this method!

• getSession() – the key to performing database operations. When we are calling Hibernate operations, we always open a session

• beginTransaction() – most database operations are performed within a ‘Transaction’ providing the scope to commit and rollback.

• commitTransaction(), rollbackTransaction(), closeSession()

Page 37: Slide 1 Application Design EE557: Server-Side Development

Slide 37

EE557: Server-Side Development

Hibernate Eclipse Project

• Download the hibernate.zip to your local harddrive

• In Eclipse, select File -> Import -> General -> Existing Projects into Workspace -> Next

• Select Archive File -> Browse to the hibernate.zip file -> Select the Project -> Next

Page 38: Slide 1 Application Design EE557: Server-Side Development

Slide 38

EE557: Server-Side Development

Creating,Reading,Updating,Deleting

• Previously covered in SQL using INSERT, SELECT, UPDATE and DELETE

• We want to use Hibernate code to automatically generate these SQL statements

• Will demonstrate using the existing template we have created i.e. the Customer bean

Page 39: Slide 1 Application Design EE557: Server-Side Development

Slide 39

EE557: Server-Side Development

Creating

• Simple create a new Customer object, populate it and ask a Hibernate Session to ‘save’ the object

Session hibernateSession = HibernateUtil.beginTransaction(); Customer customer = new Customer(); customer.setUsername("smithj"); customer.setPassword("mypass"); customer.setFirstname("John"); customer.setSurname("Smith"); customer.setEmail("[email protected]"); hibernateSession.save(customer); HibernateUtil.commitTransaction();

Page 40: Slide 1 Application Design EE557: Server-Side Development

Slide 40

EE557: Server-Side Development

Retrieving (HQL)

• As with SQL queries, a little more complicated than adding a record:

Session hibernateSession = HibernateUtil.beginTransaction(); List<Customer> allCustomers = null; Query queryResult = hibernateSession.createQuery("from Customer"); allCustomers = (List<Customer>) queryResult.list();

for (int i = 0; i < allCustomers.size(); i++) {    Customer customer = (Customer) allCustomers.get(i);     System.out.println("Customer name is : " + customer.getFirstname()

+ " " + customer.getSurname()); } HibernateUtil.commitTransaction();

Page 41: Slide 1 Application Design EE557: Server-Side Development

Slide 41

EE557: Server-Side Development

Retrieving (HQL)

• Looks suspiciously like SQL

Query queryResult = hibernateSession.createQuery("from Customer");

• This is a HQL (Hibernate Query Language) query

• Object oriented equivalent of ‘select * from Customer_David123’

• Note the case on ‘Customer’. HQL operates on the objects themselves, we are not referring to a database table called Customer. Case sensitive! (unlike SQL)

• Instead of returning rows, we are returning a List of Customer objects

• No need to convert back into object oriented form – use your beans immediately!

• More on HQL later!

Page 42: Slide 1 Application Design EE557: Server-Side Development

Slide 42

EE557: Server-Side Development

Retrieving a Unique Entity

• Returning all entities not always efficient (tables with millions of rows?)

• Frequently we want to return one entity, based on a primary key value

• We have already defined ‘id’ as the primary key of our Customer class

• How we would do it in JDBC handwritten code:

// All of the code to create connection above here String mySQLQuery = "select * from customer_david123 where id = ?"; PreparedStatement ps = con.prepareStatement(mySQLQuery); ps.setString(1, idVariable); ResultSet rs = ps.executeQuery();

if (rs.next()) { // continue code here.. manually create the Customer object using the various row // components...

Page 43: Slide 1 Application Design EE557: Server-Side Development

Slide 43

EE557: Server-Side Development

Retrieving a Unique Entity

• Using Hibernate, we do something similar to PreparedStatements

• In Hibernate we achieve ‘variable injection’ by preceding the variable name with a colon

• Because we are expecting a single entity to be returned, we don’t return a List like before. Rather we return a Customer object directly

Session hibernateSession = HibernateUtil.beginTransaction(); String queryString = "from Customer where id = :id"; Query query = session.createQuery(queryString); query.setInteger("id", idVariable); Customer customer = (Customer) query.uniqueResult(); System.out.println("Customer Name = " + customer.getFirstname() + " " +

customer.getSurname());

HibernateUtil.commitTransaction();

Page 44: Slide 1 Application Design EE557: Server-Side Development

Slide 44

EE557: Server-Side Development

Updating

• Updating is straightforward – really a combination of retriving, modifying the entity and then saving.

• Example to change the passwords of all Customer objects

• save(): new entry, update(): existing entry, alternatively saveOrUpdate()

Session hibernateSession = HibernateUtil.beginTransaction(); List<Customer> allCustomers = null; Query queryResult = hibernateSession.createQuery("from Customer"); allCustomers = (List<Customer>) queryResult.list();

for (int i = 0; i < allCustomers.size(); i++) {    Customer customer = (Customer) allCustomers.get(i);

customer.setPassword("password"); hibernateSession.update(customer);

} HibernateUtil.commitTransaction();

Page 45: Slide 1 Application Design EE557: Server-Side Development

Slide 45

EE557: Server-Side Development

Deleting

• Delete is the same as the update() example, except we use delete() instead of update()

• In previous example, update() to delete() would delete all Customer entities

• More commonly we want to delete a specific Customer (by primary key)

Session hibernateSession = HibernateUtil.beginTransaction(); Customer customer = new Customer(); customer.setId(1); hibernateSession.delete(customer); HibernateUtil.commitTransaction()

Page 46: Slide 1 Application Design EE557: Server-Side Development

Slide 46

EE557: Server-Side Development

Combined CRUD Example

• Deploy and demonstrate CRUDExample.java

• View all of the generated SQL in the output of the application

Page 47: Slide 1 Application Design EE557: Server-Side Development

Slide 47

EE557: Server-Side Development

Moving Database Vendor

• Consider our previous example (and any other code we might write). To move:

Handwritten SQL• Rewrite all ‘CREATE TABLE’ statements and any other DDL• Download new JDBC JAR file, import into project• Rewrite all methods containing JDBC code (potentially)• Debug and test SQL

Hibernate• Download new JDBC JAR file, import into project• Edit 5 lines in hibernate.cfg.xml

Page 48: Slide 1 Application Design EE557: Server-Side Development

Slide 48

EE557: Server-Side Development

Hibernate Query Language

• Why learn another query language!? I just spent ages learning SQL!

• Number of differences between SQL and HQL

1. Different syntax – need to be learned separately 2. Database Independence: HQL is database independent, SQL is not3. Relational vs Object Based: HQL is object based, SQL is relational4. Relationship with Database Structure: in SQL, statements explicitly refer to the database table and column names. In HQL instead we rely on the mappings. Hence changes in database structures, renaming of tables and fields are easier to handle under HQL. Only the mappings need to be changed, not the HQL

Later on we will look at the Criteria API which will even remove much of theNeed to learn HQL

Page 49: Slide 1 Application Design EE557: Server-Side Development

Slide 49

EE557: Server-Side Development

Basic HQL

To retrieve all Customer objects:

Session session = HibernateUtil.beginTransaction(); Query query = session.createQuery("from Customer"); List customers = query.list();

for (int i = 0; i < customers.size(); i++) { Customer customer = (Customer) customers.get(i); // Now we can do whatever we want with these objects System.out.println("Customer firstname is " + customer.getFirstname());

}

Page 50: Slide 1 Application Design EE557: Server-Side Development

Slide 50

EE557: Server-Side Development

Basic HQL

• Don’t always want to return all columns

• To return particular columns only

Query query = session.createQuery("SELECT firstname from Customer"); List names = query.list(); for (int i = 0; i < names.size(); i++) {

String name = (String) names.get(i); System.out.println("Name is " + name);

}

Example with a where clause:Query query = session.createQuery("from Customer where firstname='David'); // List results in the usual manner using Customer objects

Page 51: Slide 1 Application Design EE557: Server-Side Development

Slide 51

EE557: Server-Side Development

Basic HQL

HQL where clause with a unique result:Query query = session.createQuery("from Customer where id=1”); Customer customer = (Customer) query.uniqueResult();

Using variable injection:Query query = session.createQuery("from Customer where id= :idval");query.setInteger("idval", 1); Customer customer = (Customer) query.uniqueResult();

Ordering ResultsQuery query=session.createQuery("from Customer as c order by c.firstname ASC");

Group by/HavingQuery query = session.createQuery("from Customer as c GROUP BY c.id

HAVING c.id > 2");

Page 52: Slide 1 Application Design EE557: Server-Side Development

Slide 52

EE557: Server-Side Development

Basic HQL

• Batch Calls (ie. Deletes and updates on large numbers of records)

Query query = session.createQuery("delete Customer where firstname='John'"); int rowCount = query.executeUpdate(); System.out.println(rowCount + " rows were deleted from the database table");

• Native SQL

Can call native SQL using: session.createSQLQuery(...sql...) These queries will return Lists of objects (Strings, Integers etc.) which must be manually cast to their appropriate types

Page 53: Slide 1 Application Design EE557: Server-Side Development

Slide 53

EE557: Server-Side Development

Criteria API

• While HQL is an improvement it is still another query language to learn/use

• Hibernate Criteria API takes Hibernate to an even more intuitive object-oriented approach

• Criteria API allows us to create both simple and complex queries without using any query language

How it works

1. Create an instance of the Customer class2. Populate the properties that we wish to search against3. Pass this populated class to Hibernate as an example4. Hibernate uses the class to return all matching Entities

Page 54: Slide 1 Application Design EE557: Server-Side Development

Slide 54

Annotated Beanpackage edu.ee.beans; import javax.persistance.*;

@Entitypublic class Customer {

private int id; private String username; private String password; private String firstname; private String surname; private String email;

public Customer(int id, String username, String password, String firstname, String surname, String email) {

super(); this.id = id; this.username = username; this.password = password; this.firstname = firstname; this.surname = surname; this.email = email;

} public Customer() { }

@Id@GeneratedValuepublic int getId() { return id; } public void setId(int id) { this.id = id; } …..

….. other getter and setter methods as before…..

Page 55: Slide 1 Application Design EE557: Server-Side Development

Slide 55

EE557: Server-Side Development

Criteria API

• To obtain the list of all of our customers who have a firstname 'John', we can use the Criteria API in the following way:

Customer customer = new Customer(); customer.setFirstname('John'); // This is the situation we want to search for Example example = Example.create(customer); // We have now created an 'Example' object Criteria criteria = session.createCriteria(Customer.class); // Ask Hibernate to create a Criteria object for this bean criteria.add(example); // Add the example to the Criteria object List results = criteria.list(); // Obtain the List of Customer objects which matches the criteria

Page 56: Slide 1 Application Design EE557: Server-Side Development

Slide 56

EE557: Server-Side Development

Criteria API

• To search against more fields, simply add another set method customer.setSurname(‘Smith’)

• For queries where we are expecting a single unique result Customer cust = (Customer) criteria.uniqueResult();

• Returning all Customer entities without any ‘where’ clause. We simply don’t create an example object: Criteria criteria = session.createCriteria(Customer.class);

List results = criteria.list();

• Ordering results: Criteria criteria = session.createCriteria(Customer.class); Order order = Order.asc("surname"); criteria.addOrder(order); List results = criteria.list();

Page 57: Slide 1 Application Design EE557: Server-Side Development

Slide 57

EE557: Server-Side Development

Criteria API

• Not limited to these examples - has a considerable amount of other functionality

• Not covered in this module

• CriteriaExample.java - deploy and demonstrate

Page 58: Slide 1 Application Design EE557: Server-Side Development

Slide 58

EE557: Server-Side Development

Hibernate Mappings

• The “difficult” bit in using Hibernate

• In our example so far, we simply mapped a simple Customer class to a single database table

• Generally we will have more complicated, multi-dimensional arrays and inheritance relationships

• In SQL this is normally handled by creating multiple tables and using primary/foreign key relationships between tables

• Hibernate frees us from from the requirement to do this -> however, we stillneed to specify relationships, data types etc. -> Hibernate cannot guess!

• We do this with mapping information provided in our Annotations

Page 59: Slide 1 Application Design EE557: Server-Side Development

Slide 59

EE557: Server-Side Development

One Class to One Table

• Easiest mapping which we have already provided in the examples from before

• We mapped the Customer class to the Customers_David123 table (1 to 1)

Page 60: Slide 1 Application Design EE557: Server-Side Development

Slide 60

EE557: Server-Side Development

One Class to Two Tables

• Define the first table mapping as before, specify the second table using the@SecondaryTable annotation

• Mention the second table’s name in any appropriate @Column annotations

Page 61: Slide 1 Application Design EE557: Server-Side Development

Slide 61

EE557: Server-Side Development

One Class to Two Tables

• Look at Customer2.java and OneToTwoExample.java

@Entity @Table (name="Customer_David456“)@SecondaryTable(name="Billing_David456") public class Customer2 {

@Id @GeneratedValue public int getId() {

@Column(table="Billing_David456") public String getStreet() {

return street; }

• NOTE: Don’t forget to add Customer2.java to the HibernateUtil.java file!

Page 62: Slide 1 Application Design EE557: Server-Side Development

Slide 62

EE557: Server-Side Development

Mapping Associations: One to One

• Consider our original ‘Customer’ class. Let’s introduce a new class associatedwith this Customer called ‘CreditCard’

• Credit card in turn will have it’s own properties (card number, expiry etc.

Page 63: Slide 1 Application Design EE557: Server-Side Development

Slide 63

EE557: Server-Side Development

Mapping Associations: One to One

• ‘Customer3’ class defines a property of type ‘CreditCard’ and we need the two methods getCreditCard() and setCreditCard()

• Two options on the association:

- Unidirectional Association: such as previous diagram. Customer3 has an associated CreditCard but CreditCard has no knowledge of its encapsulating Customer3 (ie. There is no Customer3 property in CreditCard class)

- Bidirectional Association: Customer3 has an associated CreditCard instance and CreditCard has an associated Customer3 instance. In this situation CreditCard has a Customer3 property and appropriate get and set methods

• Bidirection diagram on next slide

Page 64: Slide 1 Application Design EE557: Server-Side Development

Slide 64

EE557: Server-Side Development

Mapping Associations: One to One

• For this example, we will implement this bidirectional association

Page 65: Slide 1 Application Design EE557: Server-Side Development

Slide 65

EE557: Server-Side Development

Mapping Associations: One to One

• To tell Hibernate about this association, we mark getCreditCard() (in the Customer3 class) with the @OneToOne annotation

private CreditCard creditCard;

@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)@JoinColumn(name="creditcard_id") public CreditCard getCreditCard() { return creditCard; }

• Because we are linking the two tables together, this needs to be achieved using an additional column (containing our foreign key)

• Here we are indicating that this joining column will be called ‘creditcard_id’

• We will return to cascade and fetch later

Page 66: Slide 1 Application Design EE557: Server-Side Development

Slide 66

EE557: Server-Side Development

Mapping Associations: One to One

• As we are implementing a bidirectional association we must similarly annotate the CreditCard class

private Customer3 customer3;

@OneToOne(cascade=CascadeType.ALL, mappedBy="creditCard") public Customer3 getCustomer3() { return customer3; }

• We add an instance of type Customer3 to the CreditCard class (with getterand setter methods)

• Using the mappedBy attribute, we link the enclosed class (CreditCard) back to the instance variable used to link it to the enclosing class (Customer3)

• In this example, creditCard is the name of the property in the Customer3class (Note: the case on creditCard)

• We will return to cascade and fetch later

Page 67: Slide 1 Application Design EE557: Server-Side Development

Slide 67

EE557: Server-Side Development

Mapping Associations: One to One

• Let’s look at our expected database structures for these two tables:

• Look at Customer3.java, CreditCard.java and OneToOneAssociation.java

Page 68: Slide 1 Application Design EE557: Server-Side Development

Slide 68

EE557: Server-Side Development

Mapping Associations: One to Many

• One of the most common mappings we will encounter. - BankCustomer has many BankAccounts- Student has many Modules- Exam has many ExamQuestions etc.

• We will just modify our previous example (now called Customer4 and CreditCard2) to demonstrate a One-to-Many association example

• Instead of simply containing a single creditCard property of type CreditCard, Customer4 will now contain a property creditCards of type List<CreditCard2>

• Association diagram on next slide

Page 69: Slide 1 Application Design EE557: Server-Side Development

Slide 69

EE557: Server-Side Development

Mapping Associations: One to Many

Page 70: Slide 1 Application Design EE557: Server-Side Development

Slide 70

EE557: Server-Side Development

Mapping Associations: One to Many

• We indicate that there are many credit cards to a customer• The @JoinColumn provides the name of the column which will be used to

contain the foreign key to the Customer4 table

CreditCard2.class@ManyToOne @JoinColumn (name="cust_id") public Customer4 getCustomer4() { return customer4; }

Page 71: Slide 1 Application Design EE557: Server-Side Development

Slide 71

EE557: Server-Side Development

Mapping Associations: One to Many

• The  getCustomer4() method of CreditCard2 class has @ManyToOne annotation

• Hence, getCreditCards() method of Customer4 has @OneToMany annotation

• The mappedBy attribute maps to the variable name of the encapsulating class (Customer4) takes in the encapsulated entity (CreditCard2). 

Customer4.class@OneToMany(mappedBy="customer4", targetEntity=CreditCard2.class,

fetch=FetchType.EAGER, cascade=CascadeType.ALL) public List<CreditCard2> getCreditCards() { return creditCards; }

• targetEntity is required. Because the association is actually a Collection,the targetEntity class identifies the type contained in the collection. In our example, the many part relates to a List<CreditCard2> so our targetEntity has a value of CreditCard2.class

• Deploy and demonstrate: OneToManyAssociation.java

Page 72: Slide 1 Application Design EE557: Server-Side Development

Slide 72

EE557: Server-Side Development

FetchType

FetchType.LAZY:  If the FetchType is set to LAZY, when an encapsulating object is loaded, only the attributes defined directly in the class itself are loaded into memory, and any properties mapped through LAZY associations will not be loaded into memory until they are explicitly requested.

FetchType.EAGER: If the FetchType is set to EAGER, when an encapsulating object is loaded, all of the EAGERLY associated objects will be loaded into memory as well.

• Example: In Customer4.class we defined fetch=FetchType.EAGER so the database operations to obtain the List of credit cards for the customer are performed, even if Customer4.getCreditCards() is never called!

• For performance reasons, it is always preferential to minimise the load on the database and system memory -> by default most associations are set with FetchType.LAZY.

• Especially important with one to many and many to many associations wherethe impact of preloading associated properties can be significant

Page 73: Slide 1 Application Design EE557: Server-Side Development

Slide 73

EE557: Server-Side Development

CascadeType

• Common assumption that if you ‘save’ an encapsulating entity, all associatedentities are also saved. By default, this is NOT true

• Example: Our one-to-one example (Customer3 and CreditCard)To properly save an instance of a Customer3 entity and it’s associated CreditCard entity, we must do the following:

session.save(customer3);session.save(creditCard);

• Default behaviour is the require all instances to touch the Hibernate Sessionin order to be persisted

• To modify this behaviour, we have the JPA CascadeType Enumeration

• Five possible values where we can apply multiple values at once

Page 74: Slide 1 Application Design EE557: Server-Side Development

Slide 74

EE557: Server-Side Development

CascadeType

• CascadeType.PERSIST: when the encapsulating entity is saved, any associated entities will also be persisted. Note: only applies to save operation ie. When we save a Customer3 entity we also automatically save the CreditCard entity

• CascadeType.REMOVE: when the encapsulating entity is deleted, any associated entities are also deleted. ie. When we delete a Customer3 entity we also automatically delete the CreditCard entity

• CascadeType.REFRESH: when the encapsulating entity is refreshed from thedatabase any associated entities are also refreshed. ie. When we refresh/reload a Customer3 entity we also automatically refresh the CreditCard entity

Usage of above: @OneToOne(cascade=(CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH))

• CascadeType.MERGE: when an encapsulating entity is reattached to its persistent storage any changes or updates to any associated entities are merged also. Don’t get it

• CascadeType.ALL: To take advantage of all of the persist, remove, refresh and merge options, we can simply write:@OneToOne(cascade=(CascadeType.ALL))

Page 75: Slide 1 Application Design EE557: Server-Side Development

Slide 75

EE557: Server-Side Development

The End!