Great Plains    Dexterity    Dynamics     eEnterprise     Microsoft CRM    Microsoft RMS    Crystal Reports    SQL   .Net    C#      International

Phones

Toll Free: 1-866-528-0577

Office: 1-630-961-5918

Cell (consultant-on-duty): 1-630-854-0597

Email: welcome@albaspectrum.com.

Alba Spectrum Technologies

Alba Home

Great Plains Dexterity, SQL and Crystal Reports Techniques and Good Practices Whitepaper

Naming Convention

 

Choose your naming convention:

Prefix: AS_…    <<abbreviation of (A)lba (S)pectrum>>

 

Dexterity: Procedures and Functions, Forms and Windows, Variables and Types

SQL Stored Procedures

 

 

Dexterity vs. SQL Stored Procedures

Dexterity data retrieving mechanism based on

Range start, Range End, Get First and Get Next clauses is similar, however a little bit slower to cursors in Transact SQL.  Long ranges in Dexterity are good candidates for replacement by SQL stored procedures with update clause

 

For example, consider to replace following Dexterity code:

 

Range clear SOP_HDR_WORK.

Clear ‘SOP Type’ of table SOP_HDR_WORK.

Clear ‘SOP Number’ of table SOP_HDR_WORK.

 

Range start table SOP_HDR_WORK.

Get first table SOP_HDR_WORK.

While err<>EOF do

                If ‘Salesperson ID’ of table SOP_HDR_WORK = “ERIC” then

                                Edit table SOP_HDR_WORK.

Set ‘Salesperson ID’ of table SOP_HDR_WORK to “BILL”.

                Save table SOP_HDR_WORK.

End if.

Get next table SOP_HDR_WORK.

End while.

 

With the following SQL code

 

Update SOP10100 set SLPRSNID=”BILL” where SLPRSNID=”ERIC”

 

Bringing new data into table in Dexterity is based on change/edit table clauses, in SQL they are equivalent (by performance) to inserting one record at the time.

When having long cycle of change/edit table in Dexterity, consider replacement by SQL stored procedure with Insert Into clause.

 

Transact SQL Cursors vs. Update Statements

Before using cursor, consider using update statement first.  Use cursor only when there is no way for update statement.  Cursors are very slow in comparison to update statement.  The core elements of SQL performance are joins (nested loop, merge and hash joins in SQL 7.0) are deployed for regular (aggregated) SQL statements, such as update, select, insert into, but not used for cursors.

 

Dexterity and VBA

You can use ADO (or older Microsoft technologies) to access Dynamics/eEnterprise data.  Another way is using Dexterity fragments with sanscript statements

Below is the sanscript example:

 

script_str = "local boolean err_val. local string vendorclass,accountdb_str,accountcr_str. "

script_str = script_str + "release table AS_IntegSetup. "

script_str = script_str + "set 'Setup Key' of table AS_IntegSetup to 1. "

script_str = script_str + "get table AS_IntegSetup. "

 

Advantage of Dexterity – better and more flexible security.

Advantage of ADO or other Microsoft technologies – better debugging facilities.  As a rule – use Dex if you plan light Data access/modification with VBA and use VBA ADO or others when you plan heavy data access modification.  In the heavy data access or modification consider, however either deploying SQL stored procedures or writing your project in Dexterity.

 

Dexterity and 3-rd Party Dictionaries

When you need to access third party tables in your customization, for example if you need to work with Fixed Assets or Project Accounting data, that are currently in FASQL.DIC and PA7378.DIC you can use two techniques:

  1. Create tables in your customization with exactly the same name and fields as in third party tables.  If you do this – you can work with this table and in fact you will access third party table
  2. Create combined dictionary, by developer update of Dynamics.DIC with third party product, such as Fixed Assets and then transferring table definitions from the resulting Combined.DIC into your developer dictionary.  When this is done, begin your customization.  However beware of pitfall here – if you will need to upgrade this kind of customization to new version of Dynamics/eEnterprise – you will need to create fresh Combined.dic, then transfer the same tables into you NEW developer dictionary and then transfer your customization by hand, you can not use any Dexterity Utilities automzation, because this will lead to resources Ids conflicts and your customization will work unpredictable.

 

Dexterity and B-tireve/Pervasive SQL vs. Dexterity and Microsoft SQL Server

The important difference is the inclusive ranges only in B-trieve/Pervasive SQL case and both inclusive and exclusive ranges for Microsoft SQL Server.  Exclusive ranges are more flexible.  For example, if you have index in Dexterity

 

Item Number

Vendor ID

Effective Date

 

And if you want all the items with Effective Date from 01/01/00 to 02/01/00 there is no way to get it using B-trieve inclusive range and this index, however exclusive index on Microsoft SQL platform will do the job.

In the case of B-trieve you will need another index, such as

 

Effective Date

Item Number

Vendor ID

 

Crystal Reports on Pervasive SQL/B-trieve

The important drawback for Pervasive SQL/B-trieve in comparison to Microsoft SQL is absence of left joining for tables.   You can do equal joins only.  To find that, open table linking expert in Crystal, highlight any connection and right click you mouse, you will see the possible joining methods.  In the case of Pervasive all will be deemed, except the top one – equal join.  The illustration of the effect.  Imagine you have Customer record in customer master and you sometimes have Salesperson ID for the customer and other times you don’t assign Salesperson at all.  If you link Customer Master with Salesperson Master by Salesperson ID, Crystal Report will miss the records of customers, which do not have assigned salesperson (no way to link by empty field).  In order to resolve this in B-trieve you need to create Salesperson details subreport and then link this subreport by salesperson ID with main report.  Subreport can have empty data in it.

 

Another drawback for Pervasive SQL/B-trieve is the retriction for links to use key fields only (in the case of Microsoft SQL you can link any field with any other field of compatible type).

 

When designing Crystal report for MS SQL Server data, it is highly advisable to design Select statement with joins to all tables first.  This will allow you to test performance using query tools.  When this is done transfer the construction into Crystal

 

Calling Crystal Reports from VBA

 

Easy way to call Crystal Report from your VBA code for any modified form:

 

Const RPT = "D:\Clients\Hospitality Group\Invoice Status.rpt"

 

Public crwApplication As CRPEAuto.Application

Public crwReport As CRPEAuto.Report

 

Private Sub Print_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)

If SalesTransactionInquiryZoo.Type = "Invoice" Then

 

If crwApplication Is Nothing Then

                                Set crwApplication = CreateObject("Crystal.CRPE.Application")

End If

 

Set crwReport = crwApplication.OpenReport(RPT)

crwReport.ParameterFields(1).SetCurrentValue (DocumentNo)

 

crwReport.Preview

 

End If

 

Dexterity and SQL Temporary Tables

In some cases you want populate temp tables for your custom scrolling windows with SQL Stored Procedures.  Good example – you want the aggregated monthly summaries for the accounts, complying specific wildcard, such as 1XX-2XXX-XX be displayed in your scrolling window.  Dexterity in populating this table is very ineffective – it will come through all the records in GL10000 table.  The better idea to deploy stored procedure, which will take the temp table as a parameter.  Use function GetOSName.  Below is the fragment of code:

               

                {change and save will create temporary table in SQL}

                change table AS_GL_Inquiry_Detail.

                save table AS_GL_Inquiry_Detail.

                {and then we transfer the table name as a parameter}

call sp_sbRecreateSBGLIND, L_Ret_Code, Table_GetOSName(table AS_GL_Inquiry_Detail))

 

 

Reject Record Technique in Dexterity Scrolling Windows

Use reject records in fill script for the scrolling window when you don’t want the specific record from the range to be displayed.  However it is good only if the percentage of the records rejected is relatively small.  Otherwise consider creating additional key, which creates better range for this scrolling window.  Be sure that scrolling bars for scrolling window navigation suppose that the whole range is displayed and they are confused and behave strange when large percent of records is rejected.

 

Dynamics Source Code Technique

Use source code for understanding possible customization, good candidates – lookup buttons (select vendor, customer, item, etc.) and drill down buttons on your scrolling windows (drill down to specific document ).

Below is the fragment of code taken from Dynamics.DIC source code for Lookup button for SOP Document on SOP Entry window:

 

local 'Document Date' l_date.

 

 

open form SOP_Document_Lookup return to '(L) Temp Control Number'.

 

call OPEN of form SOP_Document_Lookup,

                'SOP Sort By',

                0, {return SOP Number}

                WORK,

                1, {lock the switch}

                0, {SOP Type}

                "", {SOP Number}

                "", {Customer}

                "", {Batch}

                "", {TRX Source}

                l_date,

0.        {Master Number}

 

Now in your custom window you can use slightly modified code for Lookup button, which will return the SOP Document into your field.  Just modify return to statement.

 

Custom Functions Call in Dynamics ReportWriter

If you need to call custom functions in custom reports, use prefics rw_ in function name.  The following function will return the batch comment string for SOP Document:

 

function returns string rc_batch_comment.

in string in_sop_number.

 

set 'SOP Type' of table SOP_HDR_WORK to 3.{Invoice only}

set 'SOP Number' of table SOP_HDR_WORK to in_sop_number.

 

get table SOP_HDR_WORK.

 

if err()=OKAY then

 

                set 'Batch Source' of table Batch_Headers to "Sales Entry".

                set 'Batch Number' of table Batch_Headers to 'Batch Number'

                                of table SOP_HDR_WORK.

 

                get table Batch_Headers.

 

                if err()=OKAY then

                                set rc_batch_comment to 'Batch Comment' of table Batch_Headers.

                else

                                clear rc_batch_comment.

                end if.

else

                clear rc_batch_comment.

end if.

 

Then move SOP Invoice Blank form to your customization and if user wants to include batch comment – she/he can create local filed with the function call.

Alba Home