Difference between revisions of "Using the Query Tool"

From Opentaps Wiki
Jump to navigationJump to search
(New page: A common problem with the ofbiz entity engine and delegator is that it could be difficult to construct complex queries. To solve this problem, we created an opentaps query tool, which wor...)
 
 
(23 intermediate revisions by the same user not shown)
Line 1: Line 1:
A common problem with the ofbiz entity engine and delegator is that it could be difficult to construct complex queries. To solve this problem, we created an opentaps query tool, which works with the ofbiz delegator but allows you to write your queries in familiar SQL.  The query tool could then return either lists or EntityListIterator of GenericEntity or simply lists of maps.
+
Do you ever want to write queries in SQL, because it's second nature to you by now?  Or want to use a stored procedure or [http://www.onjava.com/pub/a/onjava/excerpt/oraclejdbc_19/index.html prepared query to improve performance]?
 +
 
 +
The opentaps query tool was created to meet these needs.  It works with the ofbiz delegator but allows you to write your queries in familiar SQL.  The query tool could then return the results of your query as a ResultSet, a List of Maps, a List of entity engine GenericValues, or the entity engine's EntityListIterator.
 +
 
 +
This feature first became available in the opentaps 1.0 trunk and is available in future versions of opentaps.  For older versions of opentaps, such as 1.0.x, download the [http://sourceforge.net/tracker/index.php?func=detail&aid=1986968&group_id=145855&atid=948961 querytool.patch].  For older versions of opentaps, such as 0.9.x, you can put the query package classes into another opentaps component such as crmsfa.
  
 
== How It Works ==
 
== How It Works ==
Line 5: Line 9:
 
To use the query tool, create a QueryFactory from the delegator:
 
To use the query tool, create a QueryFactory from the delegator:
 
<pre>
 
<pre>
   String entityGroupName = "org.ofbiz";
+
   import org.opentaps.common.query.*;
   QueryFactory qf = new QueryFactory(delegator, entityGroupName);
+
  QueryFactory qf = new QueryFactory(delegator);  // creates QueryFactory from the default "org.ofbiz" group-name in entitygroup.xml
 +
   QueryFactory qf2 = new QueryFactory(delegator, "com.mine"); // in case you had a different group-name
 
</pre>
 
</pre>
  
Then, use your QueryFactory to create either an EntityQuery or a Query.  The EntityQuery can be used to cast the result of your query as lists or an EntityListIterator of GenericEntity:
+
Then, use your QueryFactory to create either a Query.  The syntax should be similar to [http://www.hibernate.org/hib_docs/reference/en/html/objectstate.html#objectstate-querying Hibernate querying]:
 
<pre>
 
<pre>
  EntityQuery query1 = qf.createEntityQuery("StatusItem", "SELECT * FROM STATUS_ITEM WHERE STATUS_TYPE_ID = 'INVOICE_STATUS'");
+
Query q = qf.createQuery("SELECT * FROM STATUS_ITEM WHERE STATUS_ID LIKE 'INVOICE%'");
  List list1 = query1.list();
 
  EntityListIterator eli = query1.eli();
 
  Iterator it2 = query1.it();
 
 
</pre>
 
</pre>
  
The Query object can be used to pass prepared statements to your database through the delegator's connection and return either a list, an iterator, or result set:
+
'''Tip We recommend that you capitalize your SQL for compatibility reasons.''' On Linux, for example, MySQL will not recognize lowercase table names.
 +
 
 +
You can then run your query in the following ways:
 
<pre>
 
<pre>
  Query query2 = qf.createQuery("StatusItem", "SELECT * FROM STATUS_ITEM WHERE STATUS_TYPE_ID = ?");
+
// run the query and get result set
  query2.setString(1, "INVOICE_STATUS");
+
q.executeQuery();
  List list2 = query2.list();
+
ResultSet rs = q.getResultSet();
  Iterator it2 = query2.iterator();
+
 
  ResultSet rs = query2.resultSet();
+
// run the query and get it back as a List of Maps or the first value as a Map
  ResultSetMetaData rsm = query2.resultSetMetaData();
+
List list1 = q.list();
 +
Map map1 = q.firstResult();
 +
 
 +
// run the query and get an EntityListIterator.  Specify the entity name and optionally a list of fields
 +
EntityListIterator eli1 = q.entityListIterator("StatusItem");
 +
EntityListIterator eli2 = q.entityListIterator("StatusItem", UtilMisc.toMap("statusId", "statusTypeId", "description"));
 +
 
 +
// run the query and get a List of GenericValues.  Specify the entity name and optionally a list of fields
 +
List list3 = q.entitiesList("StatusItem");
 +
List list4 = q.entitiesList("StatusItem", UtilMisc.toList("statusId", "statusTypeId", "description"));
 
</pre>
 
</pre>
  
Every object in the List returned from a Query will be a Map.
+
You can set parameters to your Query as if it were a PreparedStatement:
 +
<pre>
 +
Query q2 = qf.createQuery("SELECT * FROM STATUS_ITEM WHERE STATUS_ID LIKE ? AND STATUS_TYPE_ID LIKE ?");
 +
q2.setString(1, "%APPROVE%");
 +
q2.setString(2, "INVOICE%");
 +
List list5 = q2.list();
 +
</pre>
 +
 
 +
== Technical Notes ==
 +
 
 +
When the Query is first instantiated, a PreparedStatement is instantiated, and on the first call to a method which would cause the query to be executed, such as .list(), the PreparedStatement is called, a ResultSet is obtained, converted to a List, and then closed.  Subsequent calls to .list() only return the previously stored list and does not cause another query to be run.  If you need to run the query again, call .clearQueryResults();
 +
 
 +
Converting the query results to GenericValues/GenericEntities requires the use of the ofbiz entity engine's EntityListIterator.  If you use the .entityListIterator(..) method, the EntityListIterator will be returned to you, and it will handle the closing of the connection with its own .close() method.  If you use the .entitiesList(..) methods, the EntityListIterator and the ResultSet will be automatically closed.
 +
 
 +
The ResultSet is automatically closed on finalize().
 +
 
 +
The Query and QueryFactory throw a QueryException.  If GenericValues/GenericEntities are involved, they also will throw the GenericEntityException.

Latest revision as of 18:16, 27 August 2010

Do you ever want to write queries in SQL, because it's second nature to you by now? Or want to use a stored procedure or prepared query to improve performance?

The opentaps query tool was created to meet these needs. It works with the ofbiz delegator but allows you to write your queries in familiar SQL. The query tool could then return the results of your query as a ResultSet, a List of Maps, a List of entity engine GenericValues, or the entity engine's EntityListIterator.

This feature first became available in the opentaps 1.0 trunk and is available in future versions of opentaps. For older versions of opentaps, such as 1.0.x, download the querytool.patch. For older versions of opentaps, such as 0.9.x, you can put the query package classes into another opentaps component such as crmsfa.

How It Works

To use the query tool, create a QueryFactory from the delegator:

  import org.opentaps.common.query.*;
  QueryFactory qf = new QueryFactory(delegator);  // creates QueryFactory from the default "org.ofbiz" group-name in entitygroup.xml
  QueryFactory qf2 = new QueryFactory(delegator, "com.mine");  // in case you had a different group-name

Then, use your QueryFactory to create either a Query. The syntax should be similar to Hibernate querying:

 Query q = qf.createQuery("SELECT * FROM STATUS_ITEM WHERE STATUS_ID LIKE 'INVOICE%'");

Tip We recommend that you capitalize your SQL for compatibility reasons. On Linux, for example, MySQL will not recognize lowercase table names.

You can then run your query in the following ways:

 // run the query and get result set
 q.executeQuery();
 ResultSet rs = q.getResultSet();

 // run the query and get it back as a List of Maps or the first value as a Map
 List list1 = q.list();
 Map map1 = q.firstResult();

 // run the query and get an EntityListIterator.  Specify the entity name and optionally a list of fields
 EntityListIterator eli1 = q.entityListIterator("StatusItem");
 EntityListIterator eli2 = q.entityListIterator("StatusItem", UtilMisc.toMap("statusId", "statusTypeId", "description"));

 // run the query and get a List of GenericValues.  Specify the entity name and optionally a list of fields
 List list3 = q.entitiesList("StatusItem");
 List list4 = q.entitiesList("StatusItem", UtilMisc.toList("statusId", "statusTypeId", "description"));

You can set parameters to your Query as if it were a PreparedStatement:

 Query q2 = qf.createQuery("SELECT * FROM STATUS_ITEM WHERE STATUS_ID LIKE ? AND STATUS_TYPE_ID LIKE ?");
 q2.setString(1, "%APPROVE%");
 q2.setString(2, "INVOICE%");
 List list5 = q2.list();

Technical Notes

When the Query is first instantiated, a PreparedStatement is instantiated, and on the first call to a method which would cause the query to be executed, such as .list(), the PreparedStatement is called, a ResultSet is obtained, converted to a List, and then closed. Subsequent calls to .list() only return the previously stored list and does not cause another query to be run. If you need to run the query again, call .clearQueryResults();

Converting the query results to GenericValues/GenericEntities requires the use of the ofbiz entity engine's EntityListIterator. If you use the .entityListIterator(..) method, the EntityListIterator will be returned to you, and it will handle the closing of the connection with its own .close() method. If you use the .entitiesList(..) methods, the EntityListIterator and the ResultSet will be automatically closed.

The ResultSet is automatically closed on finalize().

The Query and QueryFactory throw a QueryException. If GenericValues/GenericEntities are involved, they also will throw the GenericEntityException.