Complex Data Selection Using CBSFN Cai 299
Complex Data Selection Using CBSFN Cai 299
Editor’s Note: If you have a process that requires a complex analysis of select data and
you’re finding that your performance is slowed using UBE versions or NER coding, this tip is for
you. Rick Cai demonstrates how you can employ a C Business Function to speed up this analysis
so that your front-end processes are crisp and prompt. Included in this article are the steps you’ll
want to take, along with code and SQL statements you can modify to meet your business inquiry
needs. Please note: While there may be other ways to accomplish the functionality used as the
example in this article, the technical steps and considerations remain valuable in any number of
situations.
Business Case
®
I have been a JD Edwards EnterpriseOne developer for almost eight years and I have
encountered many scenarios in which the business requirement is to perform complex criteria
selection out of a data table for calculation before any other process occurs. Most of the time I
can achieve the goal by either using a data selection on UBE versions, or using Event Rule
coding with lots of ―if/then‖ statements after performing a ―narrower-wide-open‖ selection to
circumvent it. However, I have found that sometimes I have had to use the C Business Function
to accomplish this task, especially when there is a strict performance requirement.
An example of a situation in which the C BSFN might be required would be when the company‘s
B2B or B2C website is connected to a JD Edwards EnterpriseOne ERP backend. In this setup,
whenever a user places an online order, the process requires analysis of both real time open
transactions and historic transactions by specific criteria before the system allows the user to
place a new order. Examples of such analysis/criteria might include the need to check the aging
Account Receivable information to see if the customer is delinquent or the need to check year-to-
date order totals to see if the customer is exceeding their
annual allotment when ordering high profile products.
The key concern here lies in the performance of the The key concern here lies
web service or business function invoked to process in the performance of the
the requests between the website and ERP system. web service or business
You definitely do not want the users to spend any time function invoked to
watching the website not responding. process the requests
between the website and
Let‘s take a look at a more specific example. A ERP system.
customer (SoldTo customer number: 1234567) logs
on to our B2B web site and wants to place an order for
some high-demand products for which our company has set an annual allotment for each
customer. Thus before taking the order, the website needs to check if that order will exceed the
set quota. To accomplish this, the website calls a web service that talks to a business function
that is connected to an EnterpriseOne ERP backend.
Deriving the total of historic transactions (meaning status not =980/999) of a certain
range of products (item number begin with characters as ―100‖, excluding some special
items – say ―1001‖,‖1002‖) that had been ordered from our company during fiscal year
2010 (between 1/1/2010 and 12/31/2010).
Selecting two order types: normal order (order type: SO) and free order (order type SF).
Selecting two of this customer‘s multiple ShipTo addresses, 1234568 and 1234569 (only
these two ShipTo addresses are allowed to order those products).
To translate this business inquiry request into technical terms for a developer using a SQL
statement, it is similar to the following (F42119 is the table storing the historic order data):
If the business function connecting the website to EnterpriseOne to process the inquiry is using
NER (Named Event Rule), I‘ll bet the developer had a tough time determining how to perform
complex data selection using the vanilla table I/O function in the Event rule code. It is common
practice that NER uses a generic data selection to select by SoldTo# 1234567 and/or with order
date >=110001, then based on all other criteria checks each selected record to determine
whether or not it should be included in the desired output.
A situation such as the one described above is a key reason to consider a solution that I‘ll detail
in this article that uses C code Business Function and standard JDE database related API.
You will need to be able to write C Business Functions when implementing JDE database APIs in
your business functions, so this solution is targeted primarily at JDE Developers with a working
knowledge of C BSFNs.
The EnterpriseOne Tools version used in this article is 8.98. As you can see from Figure 1, the
JDEBase is the subset API we will focus on in this article.
First and foremost, this article is not meant to be a complete replacement for the JD Edwards
EnterpriseOne API documentation, nor does it cover all the JDEBase API calls. Instead, it is
meant to be supplemental material with a specific emphasis on how to build a complex data
selection using some of the standard APIs.
The API calls and C codes presented in this article are tested using JD Edwards EnterpriseOne
8.11 SP1 and Tools Release 8.98, and should be compatible with EnterpriseOne from XE to 9.0,
although there may be some slight variations for those non-Unicode versions (XE, 8.0) in regards
to Unicode compliance in C codes.
From a developer perspective, the best way to describe JDEbase API is simply as a group of
database related APIs, as a multiplatform API for database access, and as the link between the
application and the database.
Here is the list and description of the important API calls used in this article.
As you can see from Figure 2, the parameters list of JDB_SetSelection API—the most important
one in this article—there is one critical component we need to know more about it before we can
create any complex data selection using these JDEBase APIs. That is SELECTSTRUCT, the
data structure used to store all the key information used to build the complex selection criteria.
There is not much published information regarding how SELECTSTRUCT is defined and how to
use it.
Based on what I experienced when dealing with C codes in EnterpriseOne, the best practice for
this type of scenario is to search the JDE include system file in the E811 folder or your company‘s
corresponding local installation folder. See Figures 3, 4, and 5.
According to the definition of the data structure, there are six members inside the
SELECTSTRUCT type, as described in the following table.
If you follow the procedure shown in Figures 3 through 5, you can also track down how the
member type DBREF is defined.
The key members of DBREF are shown in Figure 6, and listed in the following table.
Again, if you follow the procedure shown in Figures 3 through 5, you can track down how the
member type JDE_CMP is defined.
The validate values for JDEDB_CMP (member nCmp of the SELECT structure) shown in Figure
7 are listed in the following table.
Notes from the Oracle website pertain to the last four values:
https://support.oracle.com/CSP/ui/flash.html#tab=KBHome(page=KBHome&id=()),(page=K
BNavigator&id=(bmDocID=1092305.1&from=BOOKMARK&bmDocType=HOWTO&bmDocD
src=KB&viewingMode=1143&bmDocTitle=E1:%20BSFN:%20How%20to%20Write%20LIKE
%20Key%20Word%20SQL%20through%20a%20Business%20Function))
“JDEDB_CMP_MATCH_ALL,JDEDB_CMP_MATCH_ANY, JDEDB_CMP_MATCH_EXACT,
JDEDB_CMP_CONTAINS are for Text String Search which may cause high overhead (so do not
implement this).”
Please note that while I listed these four values in the table, they are not used in the article‘s
demonstration example.
Now that we understand how the JDEBase API should be used, we are ready to build the C Code
Business Function for a complex data selection inquiry based on sales order history F42119.
The solution is developed and tested using EnterpriseOne 8.11, and it should be compatible with
any subsequent releases of JD Edwards EnterpriseOne, assuming no major data structure
changes have been made.
The following steps were written with the assumption that the reader is familiar with business
function development using OMW and Microsoft Visual Studio .Net environment.
1. First we need to add a data structure used to pass parameters from the application
into our to-be-created function.
2. Click ―Data Structure Design‖ on the ―Design Tools‖ tab to launch DSDA for this
brand new data structure. See Figure 11.
3. We will need to create input/output parameters in the Data Structure Design Aid (see
Figure 12). To add a parameter into the Structure Members grid on the left, you‘ll
need to find the data item using the Dictionary Item grid on the right, then use the
mouse to drag it into the Structure Members grid.
For demonstration purposes, I only added four parameters and used one input
parameter [mnAddressNumber] as the customer Sold-to number (any other criteria;
for example, date range, status code range, item list, etc., will be hardcoded in the C
code), I used one output parameter [mnUnitsTransactionQty] as the totaled quantity
and two other output parameters [cErrorCode,szDescript01] to indicate the error flag
and a brief description should any error occur. See Figure 13.
Click OK to save the definition. Also remember to check in this newly created data
structure object.
4. Now we are ready for the Function. Go back to OMW to add another new object as a
business function with the name B58TEST and the description
―ComplexDataSelectionCCodeBsfn‖. Make sure to select the Business Function
option as shown in Figure 14.
As shown in Figure 15, you need to select ―C‖ for the ―Source Language‖ and
―Client/Server‖ for ―Function Location‖.
5. Click ―Start Business Function Design Aid‖ on the ―Design Tools‖ tab to launch BFDA
for this brand new function. See Figure 17.
6. As shown in Figures 18 and Figure 19, select the appropriate parent DLL; normally it
is your company‘s customized BSFN library. Then enter the detail function name and
description into the first two columns in the grid and leave the other columns default.
7. Now we can assign the data structure D58TEST created in steps 1 through 3 as
parameters for this function. See Figure 20. Highlight the row on the grid; then click
the Parameter row exit on the left.
8. See Figure 21. Find the D58TEST using the Grid Find function, and click Select.
9. Now back to the Function Design Aid. See Figure 22. Click the Typedef row exit
button to generate the data structure code into the clipboard to be used in the C code
header file.
10. Now we need to include table F42119 into the header file to make sure that the
Business Function we are creating references F42119.h. Click the table form exit as
shown in Figure 23.
11. Enter F42119 in the Related Table grid. See Figure 24. Click OK.
12. Now let‘s go back to the Function Design Aid. We are ready to create the .h and .c
files now. Click the Create form exit button to generate them. See Figure 25.
13. You will be prompted with four pop-up messages, one after another, as shown in
Figure 26. Just click YES and OK for each of them as they appear.
14. Now if you check the local fat client JDE path code directory of your development
login environment (my path is: C:\e811\DV811), as shown in Figure 27, you can see
the B58TEST.h created in the Include folder and the B58TEST.c created in the
Source folder.
15. Now we‘re back to the Function Design Aid. We can edit the .h and .c files to enter
the codes. Click the Edit form exit button. See Figure 28.
Microsoft Visual Studio .Net is launched as the edit tool and automatically opens both the
header .h file and source .c file for coding development. See Figure 29.
Figure 30: Copy Paste Data Structure Definition INTO Header File
2. Now switch to the B58TEST C source file as shown in Figure 31. The template
created by standard JDE has already segregated the main function block of the
source file into multiple segments ready for us to fill in the code.
The F42119 related table ID and index ID are referenced from F42119.h file. See
Figure 33.
4. We‘ll initialize and hardcode some variable arrays, since for demonstration purposes
we do not take all of them in as input parameters. See Figure 34.
5. Call the API JDB_InitBhvr to initialize a user and register the user within the
Database environment identified by the input parameter: ipBhvr, and return a user
handle to the connection. See Figure 35.
See Figure 36 for the syntax from the API Help Book and more detailed information.
6. Call the API JDB_OpenTable by passing into the previous API return user handle
(hUser), defined F42119 table ID (szTableID_F42119), and index ID
(idIndexF42119_SoldTo) on the SoldTo Number to initialize table request handle
hReqF42119 for further API needs. See Figure 37.
See Figure 38 for syntax from API Help Book and more detailed information.
See Figure 40 for the syntax from API Help Book and more detailed information.
8. Now we are ready to construct the WHERE clauses one by one. The most important
thing to keep in mind is to assign the appropriate value to the appropriate direct
members or lower level member of the SELECTSTRUCT as shown previously in
Figures 5, 6 and 7 of ―Introduction to JDE Database API‖.
For example, the SoldTo number should be pointing to the NID_AN8 of NID_F42119.
Therefore, they should be assigned to the member of szDict and szTable of Item1,
which is the direct member of the SELECTSTRUCT. The lpValue for the SoldTo
number is from the input parameter mnAddressNumber. Since there is only one
value needed from that address, assign number 1 to the nValues (Number of values
to be retrieved). The value for member nAndOr should be ―JDEDB_ANDOR_AND‖.
The value for member nCmp should be ―JDEDB_CMP_EQ‖. See Figure 41.
There are several things we need to change for the next one in the array--ShipTo
number (Figure 42).
The first and most important one is to advance the cursor of the array to point
to the next one.
The ShipTo number should be pointing to the NID_SHAN.
The input value is an array that contains two values to be used, so assign
number 2 to the nValues.
The value for operator nCmp should be ―JDEDB_CMP_IN‖ because any
match within those two values should count.
The Order Type WHERE clause is similar to the ShipTo Number, other than that it is
pointing to a different column (DCTO) in the table and the input value string is from
another address. See Figure 43.
The next two WHERE clauses are for the status codes; they both are pointing to the
LLTR column on the table. The major change is the operator value of parameters
nCmp: one is NOT_EQUAL_TO and the other one is
GREATER_THAN_OR_EQUAL_TO. See Figure 44.
The next WHERE clause on the list is Order Date pointing to TRDJ. It is similar to
Order Type, but it uses JDE_CMP_BW as the ―between‖ operator for the two values
contained in the array of Date range. See Figure 45.
The next two WHERE clauses are for the Item Number; they both are pointing to the
LITM column on the table. The major difference is the operator value. One is a wild
card searching for an item number beginning with character ―100‖ (Note: Make sure
you defined the variable ending with ‗%‘ as shown on Figure 32, where we defined it
as ―100%‖) and the JDEDB_CMP_LK is used as the operator. The other one for ―item
number not in array‖ is JDEDB_CMP_NI for excluding any values from the array
―itemNumberExcludedList‖ which is 1001 and 1002 as we already defined in step 3.
See Figure 46.
9. Now we can call the API JDB_SetSelection() using the Data Structure of the
SELECTSTRUCT array to initialize the selection. See Figure 47.
See Figure 48 for the syntax from the API Help Book and for more detailed
information.
See Figure 50 for the syntax from the API Help Book and for more detail information.
11. Call API JDB_Fetch() and Loop using WHILE to process through each of the
returned records from the data selection. See Figure 51.
Note: Our demonstration only requires totaling the shipped quantities. You may
need to do more logic inside the loop-while when you create your own business-
related function.
See Figure 52 for the syntax from the API Help Book and for more detailed
information.
12. After processing all the selected records, call API JDB_CloseTable() to close table
F42119 as part of the function clean up. See Figure 53.
See Figure 54 for the syntax from API Help Book and for more detailed information.
13. The last piece of code is to free the user handle by calling API
JDB_FreeBhvr(hUser). See Figure 55.
See Figure 56 for the syntax from the API Help Book and for more detailed
information.
14. Save the code in Microsoft Visual Studio .net development environment. Now the C
coding for business function is finished.
This will take us back to the Business Function Design Main Menu. Click the ―Build
Business Function‖ on the ―Design Tools‖ tab to compile and build this new function.
See Figure 58.
The Function Builder is launched to compile and build the DLL file if no error has
occurred. See Figure 59. If there is an error, you need to check your C code in the
Microsoft Visual Studio and fix it accordingly.
2. Create a simple application with one Push Button on the Form, and call the newly
built C BSFN B58TEST to test by passing in ―1234567‖ as the input parameter. See
Figure 60.
3. Turn on the debug log in JDE.ini, then run the application and click the push button.
See Figure 61.
4. Check the debug log for the SQL statement when the business function is called. The
SQL selection statement and the associated WHERE clause meets the designed
requirement exactly. See Figure 62.
5. Now the test is done and validated. You can call this function from your B2B/B2C
web service for better performance, and throw away the old NER and its time-
consuming and clumsy ―AFTER-narrower-wide-open- selection- IF-THEN-IF-THEN-
BLAH-BLAH‖.
If you don‘t want to hardcode any value, you‘ll need to build a FULL data structure, (refer
back to Figures 12-13) for that C business function to accept all the parameters you
specified for your business needs. The more generic you make your parameter list, the
less hardcoded logic you need to enter inside your function.
If there is a business requirement to do so, you can compare two columns of the same
table by utilizing the Item2 member, DataType DBREF, as shown in Figure 5, together
with the Item1 member to perform a more complex selection based on the comparison
result of the two columns.
Always keep in mind that data selection based on Indexed Field or Fields combinations is
critical to performance, especially when you're dealing with tables with tens of thousands
of records. You can either use the standard Table Design Aid tools to create indexes that
can be utilized directly when doing coding inside EnterpriseOne, or you can simply work
with your Database Administrators to use database tools to create indirect indexes that
are inside-database-but-outside-of-JDE.
My demonstration uses one table, F42119. Sometimes you may need to join multiple
tables into one business view, then use View Related APIs to perform data selection on
the business view. Please refer to the API help book for more details.
You can also boost performance and complexity by combining with the virtual JDE Table
from the database SQL view or the Materialized table. For example, you can use a SQL
view to group or summarize your transaction data into a smaller data set view based on
your business‘ inquiry criteria. You can then use this view as a ―TABLE‖ and call
JDEBase API to do more customer specific selection. If you want to learn more about
using database SQL view as virtual table in JDE, you can refer to the JDEtips article titled
"Using SQL Views in OneWorld" by Scott Beebe, published in 2003.
Sometimes you may use parentheses to set precedence on the conditions for the
selection. For example, we made a small change to the example we used in the
demonstration. Instead of having only one range of products begin with characters as
―100‖, we have two ranges of products: one begins with characters ―100‖; the other
product lines begin with characters ―900‖.
Now the pseudo code for the new SQL statement is:
To accomplish this requirement, you‘ll need to use a different data structure derived from
SELECTSTRUCT. Its name is NEWSELECTSTRUCT. If you follow the same procedure
shown in the Figures 3, 4, and 5, you can track down how the data structure
NEWSELECTSTRUCT is defined in JD Edwards EnterpriseOne.
See Figure 63. It uses new member nParen (valid values are: JDEDB_PAREN_OPEN,
JDEDB_PAREN_CLOSE and JDEDB_PAREN_NONE) to indicate the open or close of
parentheses to determine the precedence of the conditions.
Also you‘ll need to replace the API JDB_SetSelection with JDB_SetSelectionX. See
Figure 64 for the syntax from API Help Book and for more detail information.
You can refer to one standard source file, B4000780.c, for examples.
Whenever you encounter any unclear problem when building your C code Business
Function, the best practice is to search and reference existing code from standard
EnterpriseOne C Business Functions. Please see Figures 65 and 66 on how to do that in
Microsoft Visual Studio .Net environment.
o Step1 is to search the function or data structure members you are unsure about
using ―Find in Files‖ function in your JDE C codes Source folder.
o Step 2 is to click one of the returned links; it will open the corresponding source
code file and go directly to the line that has the key words you are looking for.
Figure 65: Search For Example In standard JDE C Codes Library. Step 1
Figure 66: Search For Example In standard JDE C Codes Library. Step 2
Conclusion
Performing complex criteria data selection via UBE or Normal Event Rule code can be somewhat
clumsy and lagging in performance. This is especially true when it comes to web transactions
integrating with JD Edwards EnterpriseOne as an ERP backend. This article provides you with a
better understanding of how the standard JDEBase APIs work and walks you through
development of a C code Business Function with middle level complexity data selection based on
F42119.
Ricky Cai is a JD Edwards Developer with 10+ years technical IT and JD Edwards
EnterpriseOne experience. Previous professional positions include P&G China Software
Engineer Contractor Group and U-Soft of China. Since April 2004, Ricky Cai has been employed
by Delta Faucet Company in the U.S. as a JD Edwards developer. During this period, Ricky
worked on multiple JD Edwards implementations at multiple sites, including the 2005 P2P and
Manufacturing implementation on ERP8.0 across five sites in North American, and the 2007
China Panyu E1 8.11 implementation project and 2010 JDE B2B/B2C integration with IBM
Ecommerce. You may contact the author at [email protected]. Be sure to
mention the author‘s name and/or the article title.
.
License Information: The use of JDE is granted to Klee Associates, Inc. by permission from J.D. Edwards World Source
Company. The information on this website and in our publications is the copyrighted work of Klee Associates, Inc. and is
owned by Klee Associates, Inc. NO WARRANTY: This documentation is delivered as is, and Klee Associates, Inc. makes
no warranty as to its accuracy or use. Any use of this documentation is at the risk of the user. Although we make every
good faith effort to ensure accuracy, this document may include technical or other inaccuracies or typographical errors.
Klee Associates, Inc. reserves the right to make changes without prior notice. NO AFFILIATION: Klee Associates, Inc.
and this publication are not affiliated with or endorsed by J.D. Edwards & Company. J.D. Edwards software referenced on
this site is furnished under license agreements between J.D. Edwards & Company and their customers and can be used
only within the terms of such agreements. J.D. Edwards is a registered trademark of J.D. Edwards & Company. JDE and
OneWorld are registered trademarks of J.D. Edwards World Source Company. WorldSoftware is a trademark of J.D.
Edwards World Source Company. PeopleSoft,the PeopleSoft logo, PeopleTools, PS/inVision, PeopleCode, PeopleBooks,
PeopleTalk, and Pure Internet Architecture are registered trademarks, and Intelligent Context Manager and The Real-
Time Enterprise are trademarks of PeopleSoft, Inc. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Klee Associates, Inc. is not affiliated with or endorsed by Oracle Corporation.