adding jpa-performance example
diff --git a/jpa-performance/.classpath b/jpa-performance/.classpath
new file mode 100644
index 0000000..ffed07e
--- /dev/null
+++ b/jpa-performance/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="lib" path="C:/Engineering/EclipseLink/extension.lib.external/mysql-connector-java-5.0.7-bin.jar"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.persistence.core"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.persistence.jpa"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/javax.persistence 2.0.0"/>
+ <classpathentry kind="lib" path="C:/Engineering/EclipseLink/extension.oracle.lib.external/ojdbc6.jar"/>
+ <classpathentry kind="lib" path="C:/Engineering/EclipseLink/dev/eclipselink.jar" sourcepath="/org.eclipse.persistence.core/src"/>
+ <classpathentry kind="output" path="classes"/>
+</classpath>
diff --git a/jpa-performance/.project b/jpa-performance/.project
new file mode 100644
index 0000000..a3b9f80
--- /dev/null
+++ b/jpa-performance/.project
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.persistence.example.jpa.performance</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ </natures>
+</projectDescription>
diff --git a/jpa-performance/build.xml b/jpa-performance/build.xml
new file mode 100644
index 0000000..c299be7
--- /dev/null
+++ b/jpa-performance/build.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir="." default="build" name="org.eclipse.persistence.example.jpa.performance">
+ <property environment="env"/>
+ <property name="JDBC_LIB" value="./mysql-connector-java-5.0.7-bin.jar"/>
+ <property name="JDBC2_LIB" value="./ojdbc6.jar"/>
+ <property name="JPA_LIB" value="./persistence.jar"/>
+ <property name="ECLIPSELINK_LIB" value="./eclipselink.jar"/>
+ <property name="AGENT" value="-javaagent:${ECLIPSELINK_LIB}"/>
+ <property name="debuglevel" value="source,lines,vars"/>
+ <path id="example.classpath">
+ <pathelement location="classes"/>
+ <pathelement location="${JDBC_LIB}"/>
+ <pathelement location="${JDBC2_LIB}"/>
+ <pathelement location="${JPA_LIB}"/>
+ <pathelement location="${ECLIPSELINK_LIB}"/>
+ </path>
+ <target name="init" depends="clean">
+ <mkdir dir="classes"/>
+ </target>
+ <target name="clean">
+ <delete dir="classes"/>
+ </target>
+
+ <target depends="init" name="build">
+ <echo message="${ant.project.name}: ${ant.file}"/>
+ <javac debug="true" debuglevel="${debuglevel}" destdir="classes">
+ <src path="src"/>
+ <exclude name="**/.svn/**"/>
+ <classpath refid="example.classpath"/>
+ </javac>
+ <copy file="src/META-INF/persistence.xml" todir="classes/META-INF"/>
+ <copy file="src/META-INF/order-orm.xml" todir="classes/META-INF"/>
+ </target>
+
+ <target name="test" depends="build">
+ <java classname="example.Test"
+ maxmemory="512m"
+ fork="true">
+ <classpath refid="example.classpath"/>
+ </java>
+ </target>
+
+ <target name="test-opt" depends="build">
+ <java classname="example.TestOptimized"
+ maxmemory="512m"
+ fork="true">
+ <jvmarg value="${AGENT}"/>
+ <classpath refid="example.classpath"/>
+ </java>
+ </target>
+</project>
diff --git a/jpa-performance/jpa-performance.zip b/jpa-performance/jpa-performance.zip
new file mode 100644
index 0000000..f6ce764
--- /dev/null
+++ b/jpa-performance/jpa-performance.zip
Binary files differ
diff --git a/jpa-performance/src/META-INF/order-orm.xml b/jpa-performance/src/META-INF/order-orm.xml
new file mode 100644
index 0000000..53a3650
--- /dev/null
+++ b/jpa-performance/src/META-INF/order-orm.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings version="2.1"
+ xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <named-query name="findCustomByName">
+ <query>Select c from Customer c where c.name = :name</query>
+ <hint name="eclipselink.query-results-cache" value="true"/>
+ </named-query>
+ <entity class="model.Order">
+ <table-generator name="ORD_SEQ" allocation-size="500"/>
+ </entity>
+ <entity class="model.Customer">
+ <table-generator name="CUST_SEQ" allocation-size="500"/>
+ </entity>
+
+</entity-mappings>
\ No newline at end of file
diff --git a/jpa-performance/src/META-INF/persistence.xml b/jpa-performance/src/META-INF/persistence.xml
new file mode 100644
index 0000000..b38073a
--- /dev/null
+++ b/jpa-performance/src/META-INF/persistence.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
+ version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
+ <persistence-unit name="order-old" transaction-type="RESOURCE_LOCAL">
+ <class>model.Order</class>
+ <class>model.OrderLine</class>
+ <class>model.Customer</class>
+ <properties>
+ <!-- Change this to access your own database. -->
+ <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
+ <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test" />
+ <property name="javax.persistence.jdbc.user" value="test" />
+ <property name="javax.persistence.jdbc.password" value="password" />
+ <property name="eclipselink.ddl-generation" value="create-tables" />
+ <!-- property name="eclipselink.logging.level" value="FINE" /-->
+ <property name="eclipselink.logging.level" value="off" />
+ </properties>
+ </persistence-unit>
+ <persistence-unit name="order" transaction-type="RESOURCE_LOCAL">
+ <class>model.Order</class>
+ <class>model.OrderLine</class>
+ <class>model.Customer</class>
+ <properties>
+ <!-- Change this to access your own database. -->
+ <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+ <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+ <property name="javax.persistence.jdbc.user" value="scott" />
+ <property name="javax.persistence.jdbc.password" value="tiger" />
+ <property name="eclipselink.ddl-generation" value="create-tables" />
+ <property name="eclipselink.logging.level" value="off" />
+ </properties>
+ </persistence-unit>
+ <persistence-unit name="order-opt" transaction-type="RESOURCE_LOCAL">
+ <!-- Optimization #7, 8 - sequence preallocation, query result cache -->
+ <mapping-file>META-INF/order-orm.xml</mapping-file>
+ <class>model.Order</class>
+ <class>model.OrderLine</class>
+ <class>model.Customer</class>
+ <properties>
+ <!-- Change this to access your own database. -->
+ <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
+ <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
+ <property name="javax.persistence.jdbc.user" value="scott" />
+ <property name="javax.persistence.jdbc.password" value="tiger" />
+ <property name="eclipselink.ddl-generation" value="create-tables" />
+ <!-- Optimization #9 - statement caching -->
+ <property name="eclipselink.jdbc.cache-statements" value="true" />
+ <!-- Optimization #10 - batch writing -->
+ <property name="eclipselink.jdbc.batch-writing" value="JDBC" />
+ <property name="eclipselink.jdbc.batch-writing.size" value="1000" />
+ <!-- Optimization #11 - disable caching for batch insert (caching only improves reads, so only adds overhead for inserts) -->
+ <property name="eclipselink.cache.shared.default" value="false" />
+ <!-- Except for Customer which is shared by orders -->
+ <property name="eclipselink.cache.shared.Customer" value="true" />
+ <!-- Optimization #12 - turn logging off -->
+ <!-- property name="eclipselink.logging.level" value="FINE" /-->
+ <property name="eclipselink.logging.level" value="off" />
+ <!-- Optimization #13 - close EntityManager on commit, to avoid cost of resume -->
+ <property name="eclipselink.persistence-context.close-on-commit" value="true" />
+ <!-- Optimization #14 - avoid auto flush cost on query execution -->
+ <property name="eclipselink.persistence-context.flush-mode" value="commit" />
+ <!-- Optimization #15 - avoid cost of persist on commit -->
+ <property name="eclipselink.persistence-context.persist-on-commit" value="true" />
+ </properties>
+ </persistence-unit>
+</persistence>
diff --git a/jpa-performance/src/example/Test.java b/jpa-performance/src/example/Test.java
new file mode 100644
index 0000000..fca0cb9
--- /dev/null
+++ b/jpa-performance/src/example/Test.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.Query;
+
+import model.*;
+
+/**
+ * Simulates a migration of 100,000 objects from MySQL to Oracle.
+ * @author James Sutherland
+ */
+public class Test {
+
+ public static int CUSTOMERS = 1000;
+ public static int ORDERS = 10;
+ public static int ORDERLINES = 10;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ Test test = new Test();
+ test.setupDatabase();
+ test.migrateDatabase();
+ test.verifyMigration();
+ } catch (Exception error) {
+ error.printStackTrace();
+ }
+ }
+
+ /**
+ * Setup the original database that is to be migrated (normally this would be an existing database).
+ * This is not part of the test.
+ */
+ public void setupDatabase() {
+ System.out.println("Setting up database.");
+ EntityManagerFactory emf = Persistence.createEntityManagerFactory("order-old");
+ EntityManager em = emf.createEntityManager();
+ // Check if database exists.
+ boolean recreate = false;
+ long count = (Long)em.createQuery("Select count(c) from Customer c").getSingleResult();
+ long count2 = (Long)em.createQuery("Select count(o) from Order o").getSingleResult();
+ if ((count != CUSTOMERS) || (count2 != (ORDERS * CUSTOMERS))) {
+ recreate = true;
+ em.getTransaction().begin();
+ em.createQuery("Delete from OrderLine ol").executeUpdate();
+ em.createQuery("Delete from Order o").executeUpdate();
+ em.createQuery("Delete from Customer c").executeUpdate();
+ em.getTransaction().commit();
+ }
+ if (recreate) {
+ // Create 100 customers with 100 orders with 10 order lines ~= 100,000 objects.
+ for (int index = 0; index < CUSTOMERS; index++) {
+ em.getTransaction().begin();
+ Customer customer = new Customer();
+ customer.setName("Cust#" + index);
+ for (int index2 = 0; index2 < ORDERS; index2++) {
+ Order order = new Order();
+ order.setDescription("Order#" + (index * ORDERS + index2));
+ order.setCustomer(customer);
+ for (int index3 = 0; index3 < ORDERLINES; index3++) {
+ OrderLine orderLine = new OrderLine();
+ orderLine.setDescription("OrderLine#" + ((index * ORDERS) + (index2 * ORDERLINES) + index3));
+ orderLine.setLineNumber(index3);
+ orderLine.setCost(new BigDecimal(index3 * 100 + index2 + 5.99));
+ order.addOrderLine(orderLine);
+ }
+ em.persist(order);
+ }
+ em.getTransaction().commit();
+ em.clear();
+ }
+ }
+ emf.close();
+ emf = Persistence.createEntityManagerFactory("order");
+ em = emf.createEntityManager();
+ // Clear any data from new database from previous runs.
+ em.getTransaction().begin();
+ em.createQuery("Delete from OrderLine ol").executeUpdate();
+ em.createQuery("Delete from Order o").executeUpdate();
+ em.createQuery("Delete from Customer c").executeUpdate();
+ em.getTransaction().commit();
+ em.close();
+ emf.close();
+ System.out.println("Setup complete.");
+ }
+
+ public void migrateDatabase() {
+ EntityManagerFactory emf = Persistence.createEntityManagerFactory("order");
+ EntityManager em = emf.createEntityManager();
+ EntityManagerFactory emfOld = Persistence.createEntityManagerFactory("order-old");
+ EntityManager emOld = emfOld.createEntityManager();
+ System.out.println("Migrating database.");
+ long start = System.currentTimeMillis();
+ Query query = emOld.createQuery("Select o from Order o");
+ List<Order> orders = query.getResultList();
+ em.getTransaction().begin();
+ // Reset old Ids, so they are assigned from the new database.
+ for (Order order : orders) {
+ order.setId(0);
+ order.getCustomer().setId(0);
+ }
+ for (Order order : orders) {
+ em.persist(order);
+ for (OrderLine orderLine : order.getOrderLines()) {
+ em.persist(orderLine);
+ }
+ }
+ em.getTransaction().commit();
+ em.close();
+ emOld.close();
+ System.out.println("Migration complete.");
+ long end = System.currentTimeMillis();
+ System.out.println("Total time:" + (end - start));
+ emf.close();
+ emfOld.close();
+ }
+
+ /**
+ * Verify the correct number of objects were migrated.
+ */
+ public void verifyMigration() {
+ System.out.println("Verifying migration.");
+ EntityManagerFactory emf = Persistence.createEntityManagerFactory("order");
+ EntityManager em = emf.createEntityManager();
+ long count = (Long)em.createQuery("Select count(c) from Customer c").getSingleResult();
+ if (count == CUSTOMERS) {
+ System.out.println("Migrated " + count + " customers.");
+ } else {
+ System.out.println("Migration failed, expected " + CUSTOMERS + " customers, migrated " + count);
+ }
+ long count2 = (Long)em.createQuery("Select count(o) from Order o").getSingleResult();
+ if (count2 == (CUSTOMERS * ORDERS)) {
+ System.out.println("Migrated " + count2 + " orders.");
+ } else {
+ System.out.println("Migration failed, expected " + (CUSTOMERS * ORDERS) + " orders, migrated " + count2);
+ }
+ long count3 = (Long)em.createQuery("Select count(ol) from OrderLine ol").getSingleResult();
+ if (count3 == (CUSTOMERS * ORDERS * ORDERLINES)) {
+ System.out.println("Migrated " + count3 + " order lines.");
+ } else {
+ System.out.println("Migration failed, expected " + (CUSTOMERS * ORDERS * ORDERLINES) + " order lines, migrated " + count3);
+ }
+ }
+}
diff --git a/jpa-performance/src/example/TestOptimized.java b/jpa-performance/src/example/TestOptimized.java
new file mode 100644
index 0000000..f32944c
--- /dev/null
+++ b/jpa-performance/src/example/TestOptimized.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial impl
+ ******************************************************************************/
+package example;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.NoResultException;
+import javax.persistence.Persistence;
+import javax.persistence.Query;
+
+import model.*;
+
+/**
+ * Simulates a migration of 100,000 objects from MySQL to Oracle.
+ * @author James Sutherland
+ */
+public class TestOptimized extends Test {
+
+ public static void main(String[] args) throws Exception {
+ // Optimization #1 - use agent
+ try {
+ Test test = new TestOptimized();
+ test.setupDatabase();
+ test.migrateDatabase();
+ test.verifyMigration();
+ } catch (Exception error) {
+ error.printStackTrace();
+ }
+ }
+
+ public void migrateDatabase() {
+ EntityManagerFactory emf = Persistence.createEntityManagerFactory("order-opt");
+ EntityManagerFactory emfOld = Persistence.createEntityManagerFactory("order-old");
+ EntityManager emOld = emfOld.createEntityManager();
+ System.out.println("Migrating database.");
+ long start = System.currentTimeMillis();
+ Query query = emOld.createQuery("Select o from Order o order by o.id");
+ // Optimization #2 - batch fetch
+ // #2 - a - join fetch
+ //Query query = emOld.createQuery("Select o from Order o join fetch o.orderLines");
+ // #2 - b - batch fetch (batch fetch is more optimal as avoids duplication of Order data)
+ query.setHint("eclipselink.batch", "o.orderLines");
+ query.setHint("eclipselink.batch.type", "IN");
+ // Optimization #3 - read-only
+ query.setHint("eclipselink.read-only", "true");
+ // Optimization #4 - pagination
+ int pageSize = 500;
+ int firstResult = 0;
+ query.setFirstResult(firstResult);
+ query.setMaxResults(pageSize);
+
+ List<Order> orders = query.getResultList();
+ boolean done = false;
+ while (!done) {
+ if (orders.size() < pageSize) {
+ done = true;
+ }
+ EntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ Query customerQuery = em.createNamedQuery("findCustomByName");
+ // Reset old Ids, so they are assigned from the new database.
+ for (Order order : orders) {
+ order.setId(0);
+ customerQuery.setParameter("name", order.getCustomer().getName());
+ try {
+ Customer customer = (Customer)customerQuery.getSingleResult();
+ order.setCustomer(customer);
+ } catch (NoResultException notPersistedYet) {
+ // Customer does not yet exist, so null out id to have it persisted.
+ order.getCustomer().setId(0);
+ }
+ }
+ for (Order order : orders) {
+ em.persist(order);
+ // Optimization #5 - avoid n^2 persist calls
+ //for (OrderLine orderLine : order.getOrderLines()) {
+ // em.persist(orderLine);
+ //}
+ }
+ em.getTransaction().commit();
+ em.close();
+ firstResult = firstResult + pageSize;
+ query.setFirstResult(firstResult);
+ if (!done) {
+ orders = query.getResultList();
+ }
+ }
+ emOld.close();
+ System.out.println("Migration complete.");
+ long end = System.currentTimeMillis();
+ System.out.println("Total time:" + (end - start));
+ emf.close();
+ emfOld.close();
+ }
+}
diff --git a/jpa-performance/src/model/Customer.java b/jpa-performance/src/model/Customer.java
new file mode 100644
index 0000000..78826cd
--- /dev/null
+++ b/jpa-performance/src/model/Customer.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+
+import javax.persistence.*;
+
+/**
+ * Customer
+ * @author James Sutherland
+ */
+@Entity
+@Table(name="PERF_CUSTOMER")
+public class Customer implements Serializable {
+ @Id
+ @GeneratedValue(generator="CUST_SEQ")
+ @TableGenerator(name="CUST_SEQ", allocationSize=1)
+ private long id;
+ @Basic
+ private String name;
+
+ public Customer() {
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/jpa-performance/src/model/Order.java b/jpa-performance/src/model/Order.java
new file mode 100644
index 0000000..13b5c1a
--- /dev/null
+++ b/jpa-performance/src/model/Order.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.*;
+
+/**
+ * Order
+ * @author James Sutherland
+ */
+@Entity
+@Table(name="PERF_ORDER")
+public class Order implements Serializable {
+ @Id
+ @GeneratedValue(generator="ORD_SEQ")
+ @TableGenerator(name="ORD_SEQ", allocationSize=1)
+ @Column(name="ORDER_ID")
+ private long id;
+ @Basic
+ private String description;
+ @Basic
+ private BigDecimal totalCost = BigDecimal.valueOf(0);
+ @OneToMany(mappedBy="order", cascade=CascadeType.ALL, orphanRemoval=true)
+ @OrderBy("lineNumber")
+ private List<OrderLine> orderLines = new ArrayList<OrderLine>();
+ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
+ private Customer customer;
+
+ public Order() {
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public BigDecimal getTotalCost() {
+ return totalCost;
+ }
+
+ public void setTotalCost(BigDecimal totalCost) {
+ this.totalCost = totalCost;
+ }
+
+ public List<OrderLine> getOrderLines() {
+ return orderLines;
+ }
+
+ public void setOrderLines(List<OrderLine> orderLines) {
+ this.orderLines = orderLines;
+ }
+
+ public Customer getCustomer() {
+ return customer;
+ }
+
+ public void setCustomer(Customer customer) {
+ this.customer = customer;
+ }
+
+ /**
+ * Add the order line to the order, and set the back reference and update the order cost.
+ */
+ public void addOrderLine(OrderLine orderLine) {
+ orderLine.setOrder(this);
+ getOrderLines().add(orderLine);
+ orderLine.setLineNumber(getOrderLines().size());
+ setTotalCost(getTotalCost().add(orderLine.getCost()));
+ }
+}
diff --git a/jpa-performance/src/model/OrderLine.java b/jpa-performance/src/model/OrderLine.java
new file mode 100644
index 0000000..3341bd9
--- /dev/null
+++ b/jpa-performance/src/model/OrderLine.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Oracle - initial impl
+ ******************************************************************************/
+package model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.*;
+
+/**
+ * OrderLine, help by Order.
+ * @author James Sutherland
+ */
+@Entity
+@Table(name="PERF_ORDERLINE")
+public class OrderLine implements Serializable {
+ @Id
+ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
+ @JoinColumn(name="ORDER_ID")
+ private Order order;
+ @Id
+ private int lineNumber;
+ @Basic
+ private String description;
+ @Basic
+ private BigDecimal cost = BigDecimal.valueOf(0);
+
+ public OrderLine() {
+ }
+
+ public OrderLine(String description, BigDecimal cost) {
+ this.description = description;
+ this.cost = cost;
+ }
+
+ public Order getOrder() {
+ return order;
+ }
+
+ public void setOrder(Order order) {
+ this.order = order;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public BigDecimal getCost() {
+ return cost;
+ }
+
+ public void setCost(BigDecimal cost) {
+ this.cost = cost;
+ }
+
+}