diff --git a/base/src/org/compiere/model/Query.java b/base/src/org/compiere/model/Query.java
index afd9799259..41fac71689 100644
--- a/base/src/org/compiere/model/Query.java
+++ b/base/src/org/compiere/model/Query.java
@@ -52,6 +52,8 @@ import org.compiere.util.Util;
*
FR [ 2726447 ] Query aggregate methods for all return types
* FR [ 2818547 ] Implement Query.setOnlySelection
* https://sourceforge.net/tracker/?func=detail&aid=2818547&group_id=176962&atid=879335
+ * FR [ 2818646 ] Implement Query.firstId/firstIdOnly
+ * https://sourceforge.net/tracker/?func=detail&aid=2818646&group_id=176962&atid=879335
* @author Redhuan D. Oon
* FR: [ 2214883 ] Remove SQL code and Replace for Query // introducing SQL String prompt in log.info
* FR: [ 2214883 ] - to introduce .setClient_ID
@@ -306,6 +308,69 @@ public class Query
}
return po;
}
+
+ /**
+ * Return first ID
+ * @return first ID
+ * @throws DBException
+ */
+ public int firstId() throws DBException
+ {
+ return firstId(false);
+ }
+
+ /**
+ * Return first ID.
+ * If there are more results and exception is thrown.
+ * @return first ID
+ * @throws DBException
+ */
+ public int firstIdOnly() throws DBException
+ {
+ return firstId(true);
+ }
+
+ private int firstId(boolean assumeOnlyOneResult) throws DBException
+ {
+ String[] keys = table.getKeyColumns();
+ if (keys.length != 1)
+ {
+ throw new DBException("Table "+table+" has 0 or more than 1 key columns");
+ }
+
+ StringBuffer selectClause = new StringBuffer("SELECT ");
+ selectClause.append(keys[0]);
+ selectClause.append(" FROM ").append(table.getTableName());
+ String sql = buildSQL(selectClause, true);
+
+ int id = -1;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try
+ {
+ pstmt = DB.prepareStatement(sql, trxName);
+ rs = createResultSet(pstmt);
+ if (rs.next())
+ {
+ id = rs.getInt(1);
+ }
+ if (assumeOnlyOneResult && rs.next())
+ {
+ throw new DBException("QueryMoreThanOneRecordsFound"); // TODO : translate
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e, sql);
+ }
+ finally
+ {
+ DB.close(rs, pstmt);
+ rs = null; pstmt = null;
+ }
+ //
+ return id;
+ }
/**
diff --git a/extend/src/test/functional/QueryTest.java b/extend/src/test/functional/QueryTest.java
index 91c666d48e..61cb02ef8b 100644
--- a/extend/src/test/functional/QueryTest.java
+++ b/extend/src/test/functional/QueryTest.java
@@ -153,6 +153,16 @@ public class QueryTest extends AdempiereTestCase
.first();
assertEquals("Invalid object", "C_Invoice", t.getTableName());
}
+
+ public void testFirstId() throws Exception
+ {
+ int id = new Query(getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName())
+ .setParameters(new Object[]{"C_Invoice", "M_InOut"})
+ .setOrderBy("TableName")
+ .firstId();
+ int expectedId = 318; // C_Invoice
+ assertEquals("Invalid ID", expectedId, id);
+ }
public void testFirstOnly() throws Exception
{
@@ -172,6 +182,25 @@ public class QueryTest extends AdempiereTestCase
});
}
+ public void testFirstIdOnly() throws Exception
+ {
+ int expectedId = 318; // C_Invoice
+ int id = new Query(getCtx(), "AD_Table", "AD_Table_ID=?", getTrxName())
+ .setParameters(new Object[]{expectedId})
+ .firstIdOnly();
+ assertEquals("Invalid table ID", expectedId, id);
+ //
+ assertExceptionThrown(null, DBException.class, new Runnable(){
+ public void run()
+ {
+ new Query(getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName())
+ .setParameters(new Object[]{"C_Invoice", "M_InOut"})
+ .setOrderBy("TableName")
+ .firstIdOnly();
+ }
+ });
+ }
+
public void testSetClient_ID() throws Exception
{
int AD_Client_ID = Env.getAD_Client_ID(getCtx());