Beruflich Dokumente
Kultur Dokumente
This resource document contains detailed information regarding scripting best practices.
Copyright © 2004 Siebel Systems, Inc., 2207 Bridgepoint Parkway, San Mateo, CA 94404. All
rights reserved. No part of this publication may be stored in a retrieval system, transmitted, or
reproduced in any way, including but not limited to photocopy, photographic, magnetic, or
other record, without the prior agreement and written permission of Siebel Systems, Inc.
Siebel Systems, Inc. considers information included in this document to be Confidential and
Proprietary. Your access to and use of this Confidential and Proprietary Information is subject
to the terms and conditions of the Siebel License Agreement or Non-Disclosure Agreement
which has been executed and with which you agree to comply.
Table of Contents
In Acrobat, you can click on any lesson or topic to jump to that area of the resource document.
You can also use the Bookmarks feature in Acrobat to quickly navigate.
SCRIPTING FUNDAMENTALS
Scripting: Where to Begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Basic Process Flow
Basic Process Flow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1. Explore Declarative Configuration Alternatives
2. Determine Where to Put the Script: Which Object?
3. Determine Where to Put the Script: Which Event?
4. Add Error Handling Template
5. Add Method Body
6. Test
SCRIPTING BEST PRACTICES
When to Use Scripting. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Use Scripting as a Last Resort
Follow Standard Naming Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Comment Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Know When to Use Browser versus Server Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Place Code in the Correct Event Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Use Fast Script In Event Handlers that Fire Frequently. . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Runtime versus Compiled Business Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Use Option Explicit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Leverage Appropriate Debugging Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Debugging Siebel Applications
Alert and RaiseErrorText
Writing to a Text File
Using the Debugger in Siebel Tools
Using Object Manager Settings
Remove Unused Code from the Repository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Include Error Handling in All Scripts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Proper Error Handling
Error Handling in eScript
Error Handling in Siebel VB
Use RaiseError and RaiseErrorText Properly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Use Exception Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Purpose of Exception Handling
Exception Information in eScript
Exception Information in Siebel VB
Place Return Statements Correctly: eScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Centralize Browser Script Using the “Top” Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Know When to Use the Current Context versus a New Context in Server Script. . . . . . . 31
Difference Between Current and New Context
Guidelines for Choosing Context
Use Smallest Possible Scope for Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Instantiate Objects Only As Needed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Destroy Object Variables When No Longer Needed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Use Conditional Blocks To Run Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Verify Objects Returned . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Verify Object Returned is Expected One
ActiveBusObject
ActiveBusComp
ParentBusComp
Verify Field is Active before Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Leverage New Methods in Siebel 7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
New Methods
Use Proper View Mode For Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Query Only Indexed Columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Use ForwardOnly Cursor Mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Verify Existence of Valid Record After Querying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Use Switch or Select Case Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Compare the Same Condition In If/Else If . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Use the Associate Method to Create Intersection Table Records . . . . . . . . . . . . . . . . . . . . 49
Use Dynamic Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Use Logical Constants versus Literal Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Avoid Exit Function and Exit Sub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Place GotoView at the End of a Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Use DeleteRecord Method Properly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Scripting Fundamentals
Scripting: Where to Begin
Basic This flowchart outlines the basic process for developers to follow when
Process Flow writing script.
1. Explore Before writing any script, developers should explore all declarative
Declarative configuration alternatives. This is an important step! It ensures that
Configura- developers write script only when there is no configuration alternative, thus
tion
Alternatives minimizing the amount of script.
2. Determine After determining that the solution requires script, developers must
Where to Put determine where to put the script. A utility script that will be called from
the Script: many locations such as applets, business components, and business services,
Which
Object? is best implemented as a business service. This enables developers to write
the script once for use by many objects.
An alternative to writing a business service is to write the method at the
application level. Siebel Systems encourages developers to use business
services, as they can be called by workflow processes; workflow processes
cannot call custom application level methods.
If the method deals with data in a specific business component, that business
component is the most likely object for the script. Writing script at the
business component level prevents developers from having to re-write it on
applets that leverage the same underlying business component. This only
makes sense if the method is specific to a particular business component. If
the same script is seen in many business components with only slight
differences, move the script to a business service and parameterize it.
If the method controls the behavior of an applet, for example, if it is enabling
a button or hiding/showing list columns or controls, write the script at the
applet server level.
If the method facilitates interaction with the client’s desktop or
communication with the user, make the script an applet browser script.
3. Determine After determining the appropriate object, developers must determine the
Where to Put appropriate event within that object.
the Script:
Which Business component
Event? There are two ways to think of scripting a business component: proactively
and reactively. If you need to perform some sort of validation, but do not
need to change data in any record other than the current record, use the
Pre- event (for example, PreQuery, PreSetFieldValue, PreWriteRecord).
This is a proactive approach: you are trying to stop or modify something the
user is doing before it gets too far.
3. Determine Never use Pre- events to change data in a record other than the current
Where to Put record. The Pre- event occurs before the Siebel application runs its own
the Script: field-level validations and other processes in the underlying C++ class that
Which
Event? might fail. If these processes fail, the Siebel application exits the Pre- event
Continued and does not roll back any changes to other objects. This could leave the
application in an inconsistent state.
To perform further processing after a change has been applied, for example,
after the application writes a record, implement a reactive script. A reactive
script typically applies to the WriteRecord event. This is quite often a
workflow process or some sort of integration. When taking a reactive
approach, it is acceptable to manipulate data in records other than the
current record.
Applet
Most scripting for applet browser functionality will originate in the
Applet_PreInvokeMethod event. This is where developers can trap methods
invoked on an applet. Methods that interact with the user’s desktop, the user,
or how the applet looks, should originate in this event. Siebel Systems
recommends not putting all of the method code in the
Applet_PreInvokeMethod event. Rather, create custom methods and call
those methods from this event.
If the method accesses data in a record other than the current record or
active business component, write a server script in the
WebApplet_PreInvokeMethod event. If the method deals with data specific
to the business component, then the business component is the appropriate
place for the method. If, however, the method deals with something specific
to the applet, write the script on the applet. Remember that you are trying to
reduce the amount of script written.
Business Service
This is the best place to write script that will be called from anywhere.
Ideally, write a method that can accept parameters to operate for a wide
range of needs. This eliminates the need to duplicate code across objects and
events, significantly simplifying maintenance efforts. Duplicating script is a
common problem which frequently leads to thousands of pages of script!
Since any script, even browser script, can call a business service, it is an ideal
location for many situations. Siebel Systems recommends not putting all of
the method script in the Service_PreInvokeMethod. Rather, break it into
smaller scripts that the Service_PreInvokeMethod event of a business service
can call.
4. Add Error Put an error/exception handling strategy in place before writing any script.
Handling This includes creating an error handling template that you can apply to all
Template scripted events. Applying the error handling skeleton to a method before
writing the method, assures two things:
• error handling is present and
• future manipulation of the method will not cause a runtime error that
goes unnoticed.
5. Add Now you are ready to write the actual method. “Sandwich” this code within
Method Body the error handling code, so that you can catch any runtime errors.
6. Test This is the last and most important step of scripting. Make sure the tests are
complete, covering all possible conditions. Failure to test completely results
in more wasted time later trying to track down a bug.
Use Scripting Do not write script if there is a way to implement the required functionality
as a Last through configuration. Declarative configuration is easier to maintain and
Resort upgrade, leading to a lower total cost of ownership.
Before writing any script, Siebel Systems highly recommends that you review
the media-based training (MBT) titled Declarative Alternatives to Siebel
Scripting. For more information about this MBT, log on to Siebel University at
http://siebeluniversity.siebel.com.
Preferred alternatives to scripting include
• Field validation
• User properties
• Workflow
• Personalization
• Run-time events
• State model
Have the project team agree upon a standard way of naming variables so that
the scope and data type are identified easily. This significantly simplifies
maintenance and troubleshooting efforts.
Data types
Data Type Prefix
Integer I
String S
Boolean B
Float f
Scope
Scope Modifier
Global Scope (only applicable for G_
Siebel VB)
Module/Instance Scope M_ or i_
Function or Local Scope No modifier or l_
Comment Code
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Name: MyProcedure()
' Module: BusComp [Account]
' Arguments:
' oBC1BusComp BusComp for ABC (positioned)
' oBC2BusComp BusComp for XYZ (not yet
' positioned)
'
' Return Value: Integer ContinueOperation -> Relationship is
' OK
' CancelOperation -> Relationship is
' not OK
'
' Used Globals: gintCheckIt Set to 1 in
' [Quote].[BusComp_ChangeRecord]
' Evaluated and Reset here
'
' Static Vars: mintChecked Set to 0 in [Account].
' [BusComp_ChangeRecord]
' Evaluated and Set to 1 here
'
' NOTE: Procedure might be called recursively!!!
' History
One of the most common issues identified during script reviews is the
inappropriate use of object events. Placing code in the wrong event handler
can lead to corrupt data and may negatively impact performance.
Do not use Siebel application Pre- events (such as PreQuery,
PreSetFieldValue, and PreWriteRecord) to manipulate data in objects other
than the one hosting the script. (See “3. Determine Where to Put the Script:
Which Event?” on page 6 for more information). The companion events, such
as Query, SetFieldValue, and WriteRecord, occur after the internal and
field-level validations succeed, and therefore are the appropriate events for
such manipulation. For example, the WriteRecord event fires after the record
writes successfully. When this event fires, you know that the record exists;
therefore it is safe to create or modify data in other objects, without fearing
orphaned records or an inconsistent state of the application.
eScript examples
BusComp_PreSetFieldValue Field level validation
BusComp_PreWriteRecord Record level validation
BusComp_SetFieldValue Field triggered actions
BusComp_WriteRecord Record triggered actions
Example: synchronizing two business
components or creating activities
BusComp_PreQuery Code control over SearchSpecs
Avoid placing complex code in event handlers that fire frequently, such as
BusComp_PreGetFieldValue, as it may degrade application performance.
The PreGetFieldValue event fires at least once for every field that is
retrieved. This can amount to hundreds of calls to the event in rapid
succession. Complex script in this event handler significantly degrades
application performance.
Developers typically use script in the PreGetFieldValue event to return a
value other than the one in the database. As an alternative, developers can
use a calculated field. The calculated field holds the display value and the
calculation performs the logic. In this case, the Siebel application exposes the
calculated field, not the actual field, to the user.
For other frequently fired events, look for a configuration alternative, and if
none is available, make the script as simple as possible. One alternative for
complex calculations is to create a calculated field that uses the
InvokeServiceMethod function. More detail on this function and its suggested
use can be found in the Siebel Bookshelf.
Business services may be defined in Siebel Tools and compiled with the .srf
file, or created as runtime business services in the client user interface. The
decision on whether to make a business service compiled or runtime has no
hard and fast rules. It ultimately depends on what you intend the service to
do and how frequently you expect the code in the business service to change.
Runtime business services are not compiled into the .srf file. The database
stores them as records and you can change them at any time. The next time a
runtime service executes, it uses the changes to the definition. This makes
them useful for logic that changes frequently and logic that you need to
change without deploying a new .srf file. The drawback to a runtime business
service is that anyone with access to the view can see the code. This can pose
a security problem.
Runtime business services can be useful in a development environment to test
frequent changes to scripts by using the business service simulator. Since no
compiling is required, code development may be faster in the runtime
environment. Once the code is complete and tested through the simulator,
the developer can choose whether the business service should remain as a
runtime service or if it should be migrated to Siebel Tools.
Compiled business services are defined in Siebel Tools and represent a
functionality that needs more security and is not likely to change. You must
compile and implement a new .srf file to implement any changes. Because
these business services are compiled, they provide more security than
runtime services and they are faster to load.
Note: If you define a business service called MyService as a runtime business
service and as a compiled business service, the compiled version executes and
the runtime version is ignored. For clarity, if you migrate a business service
from a runtime version to a compiled version, you should inactivate or delete
the runtime version so that it is clear to all developers that the runtime
version is no longer being used.
Option Explicit requires that you explicitly declare every variable. The
compiler returns an error if the Siebel application uses a variable before
declaration; thus simplifying debugging efforts.
Without Option Explicit, the Siebel application defines and dimensions
variables on the fly.
Example: if you defined a variable called ls_description, and later reference
the variable as ls_dscription (missing an ‘e’), Option Explicit catches that a
variable is being used that has not been defined. Without Option Explicit, the
application defines a new variable as ls_dscription.
Since Option Explicit only evaluates during compile time, there is no
performance impact.
Debugging It is essential that you understand how to debug Siebel applications. There are
Siebel four basic techniques:
Applications
• Use alerts or RaiseErrorText methods to pop up message boxes
• Write to a file using Trace or custom methods
• Use the Siebel Debugger
• Use object manager level logging
Alert and The alert method in browser script and the RaiseErrorText method in server
RaiseError- script enable you to display message boxes to the user.
Text
The RaiseErrorText method stops the execution of a script; therefore, it is
only appropriate for a quick check of something and is not a good way to
debug scripts where the source of the error is hard to determine.
Alerts do not stop the execution of browser scripts and therefore are a quick
and easy way to debug browser scripts.
Writing to a The most common way to debug a script is to write information to a text file.
Text File Accomplish this using the Trace function or an Siebel VB or eScript function.
Using Trace, you can write the actual SQL to a file.
Using the This is a useful tool for visually stepping through the code and looking at the
Debugger in values of variables real time. You can set break points anywhere until you
Siebel Tools isolate a problem.
This graphic shows the two locations in the Siebel client application where
object manager logging is turned on.
For the log level changes to take effect immediately, modify the Current
Value parameter.
If you want to keep a record of obsolete code before removing it, you can do
an export from Siebel Tools to save a copy of the script. To export a script to a
text file, open the script editing window for the object in question, then
choose File > Export. The script for all methods on that object will be
exported to a file of type .js if the script is written in eScript, or .sbl if it is
written in Siebel VB.
Alternatively, you can create an archive file, of file type .sif, with the object
containing the script. Archive files contain all property definitions for the
object, whereas a .js or .sbl file only contains the script.
Remove Empty Methods
Example of empty method in Siebel VB
Sub Application_Start (CommandLine As String)
End Sub
The event handler for an empty method shows up as Active in Siebel Tools.
This can be confusing to developers who think the event is scripted due to its
Active status. Also, empty methods can cause a small performance hit as the
interpreter may run through the event handler unnecessarily.
Example:
function illustrateErrorHandling()
{
try
{
/*The try block encompasses all statements that
could cause an exception. */
...executable code goes here...
}//end try
The try keyword precedes a block of normal processing code that may throw
an exception.
Error catch(e)
Handling in {
eScript
Continued if(defined(e.errText))
{
TheApplication().RaiseErrorText(“An exception occurred ” +
“in the “ + arguments.callee +
“ of the “ + this.Name() + “ object. “ +
“ERROR: ” + e.errText +
“STACK: ” + e.toString());
}
else
{
TheApplication().RaiseErrorText(“An exception occurred ” +
“in the “ + arguments.callee +
“ of the “ + this.Name() + “ object. “ +
“ERROR: ” + e.toString());
}
}//end catch
The catch keyword precedes a block of exception handling code. After a try
block throws an exception, control over the program flow switches to the first
catch block following it.
Use two methods to avoid hard coding the object and method names.
• arguments.callee substitutes the method name in which the code is
running.
• this.Name() substitutes the object name in which the script is running.
Using these methods allows developers to copy this catch block into any
eScript server script routine without changing it at all.
Error finally
Handling in {
eScript
Continued // This block will always be called whether an exception is
// thrown or not.
// put the cleanup code here, for example:
bcContact = null;
boAccount = null;
}
The finally block always executes, so it is an ideal location for the final
release of resources.
Error There are two strategies for handling unexpected runtime errors in Visual
Handling in Basic:
Siebel VB
1. On Error Goto <label>: traps runtime errors in the Err object and
transfers control immediately to the label specified. It can perform code
cleanup and write the error parameters to a log file, after which the
procedure may gracefully exit and inform the user of the error condition.
2. On Error Resume Next: traps the runtime error in the Err object and
continues right along as though nothing happened. This is a dangerous
form of error handling because it essentially ignores all errors. If no error
handling is done immediately after Err object detects an error, it will
continue processing as if nothing happened.
errorhandler:
Set lBC_test = Nothing
Set lBO_test = Nothing
In eScript, you can obtain the method name dynamically from a native
property of the method called “arguments”. This is an array of parameters
specific to the method being invoked.
Example:
if(defined(e.errText))
{
TheApplication().RaiseErrorText(“An exception occurred ” +
“in the “ + arguments.callee + “ of the “ + this.Name()
+ “ object. “ + “ERROR: ” + e.errText + “STACK: ”
+ e.toString());
}
else
{
TheApplication().RaiseErrorText(“An exception occurred ” +
in the “ + arguments.callee + “ of the “ + this.Name()
+ “ object. “ + “ERROR: ” + e.toString());
}
Exception In Siebel VB, the Err object stores the error information. Because Siebel VB
Information does not include properties that store the method name, you must hard code
in Siebel VB the method name in the string passed to the RaiseErrorText method.
Example:
If Err <> 0 Then
TheApplication.RaiseErrorText "An error has occurred " & _
“illustrateExceptionHandling method ” & Chr$(13) & _
"in the " & Me.Name & _
" object. " & Chr$(13) & _
"Error number: " & Err & Chr$(13) & _
"Error text: " & Error$ & Chr$(13) & _
"Error line: " & Erl
End If
In browser script, top is a shortcut to the top level document. Using the top
object, developers can write a browser script function once and call it from
anywhere within the browser aspect of objects.
Note: Scripted objects have a server side aspect which can only call server
script and a browser side aspect which can only call browser script. Thus the
top object, being a browser script object, can only be referenced from
browser script. This is useful for any function which needs to interact
programmatically with a client application or desktop, that would also need
to be called from multiple places in the application.
The following example provides a logging function in the top object:
1. Assign a pointer for the method to the top object:
• Include Top in (general) (declarations) of Application object
top.log = trace_log;
This step assigns a function pointer to the top window object of the
application, which any browser script can use.
2. Implement the method at the application level
function trace_log(as_text)
{
...include trace logic here.
{
After adding the function to the (general) (declarations) section, you will see
it appear as a separate function in the script window, as shown below:
Difference • Current (or UI) context deals with objects that the Siebel application
Between created to support data that are currently available to the user.
Current and
New Context • New (or Non-UI) context is a set of objects instantiated in script that
have no tie to any objects or data that the user is currently viewing.
Keeping these two straight is important because the user may see
programmatic manipulations of data if you use the wrong context. For
example, consider a script running in any event of the Contact business
component that needs to get a reference to the Contact business component
to do a comparison or lookup.
This code returns a reference to the current instance of the Contact business
component:
bc = this.BusObject().GetBusComp(“Contact”);
If this code is executed while a user is watching the user interface, the user
sees any programmatic manipulations of the data.
Equivalent ways of getting a reference to the current Contact business
component instance are
bc = TheApplication().ActiveBusObject().GetBusComp(“Contact”);
bc = this;
To prevent users from seeing data manipulation that the script does, create a
new, or non-UI, instance of the Contact business component.
bo = TheApplication.GetBusComp(“Contact”);
bc = bo.GetBusComp(“Contact”);
The difference here is the business object. Since all business components live
within an enclosing business object’s context, it is the business object that
makes the difference. In this previous code example, the application created
a new instance of the Contact business object, enabling data manipulation to
occur outside of the current context.
Note that when the current record is instantiated and modified in a non-UI
context instance, the warning message “The selected record has been
modified by another user since it was retrieved” will be displayed to the user.
This message appears because the script has modified the current record, and
a refresh is necessary for the user to see the current field values. Therefore,
if the script is going to update the current record, it may be preferable to use
the UI context to avoid this message.
It is far better to declare and use objects where they are needed and pass
them as parameters to other methods.
Incorrect order
1. Create objects
2. Evaluate condition
3. Use objects
Tightly couple object destruction with error handling to ensure that the Siebel
application destroys objects in success and in failure. Therefore, destroy
objects in the finally clause as this clause always executes, regardless of
whether the method exits successfully or with errors.
finally
{
ChildObject = null;
ParentObject = null;
}
Just as objects should be instantiated only as needed, code should be run only
as needed.
A typical example is in the BusComp_PreSetFieldValue event. Code in this
event is usually associated with a specific field, not all fields. Check which
field the code is modifying before going any further.
Example:
function BusComp_PreSetFieldValue(FieldName, FieldValue)
{
switch(FieldName)
{
case “Status”:
…do something…
break;
…
}
…
}
Verify Object Always verify that the object returned is the one expected, especially when
Returned is calling methods such as ActiveBusObject, ActiveBusComp, and
Expected ParentBusComp.
One
ActiveBus- ActiveBusObject returns the business object for the business component of
Object the active applet. When a business component can be the child of more than
one business object, check which object is actually returned from a call to
this method.
ActiveBusObject only makes sense if used in a script running in the
application object or in a business service. Script running in an applet or in a
business component should use:
• Me.BusObject (in an applet and in a business component)
• this.BusObject(); (in an applet and in a business component)
eScript Example:
if(TheApplication().ActiveBusObject().Name() == “some name”)
{
…code here…
}
Siebel VB Example:
If TheApplication.ActiveBusObject.Name = “some name” Then
…code here………
End If
ActiveBus- ActiveBusComp returns the business component associated with the active
Comp applet. When running script outside of a business component, verify the
active business component with a call to this method.
ParentBus- ParentBusComp returns the parent business component when given the child
Comp business component of a link. Always make sure that a business component
reference obtained with the ParentBusComp method is valid and is the one
expected. Two situations could cause no reference to return:
• The business component is the parent and has no parent, such as the
Account business component in the Account business object.
• The link that established a parent/child relationship in the business object
has been removed or changed.
eScript Example
var lBC_parent = this.ParentBusComp();
if(lBC_parent != null && lBC_parent.Name() == “some name”)
{
……code……
}
Siebel VB Example
Set lBC_parent = Me.ParentBusComp
If Not lBC_parent Is Nothing And lBC_Parent.Name = “some name” Then
………code……
End If
In this example, the script is verifying that there is a reference before getting
the Name attribute.
Correct Use
ActivateField(<Name>);
ExecuteQuery(ForwardOnly);
GetFieldValue(<Name>);
var ls_account_products;
var ls_agreement_name;
var ls_project_name;
var ls_description;
var ls_name;
//activate the fields using the property set which has the
//field names
lbc_account.ActivateMultipleFields(lPS_FieldNames);
New Methods
Continued lbc_account.ExecuteQuery(ForwardOnly);
if (lbc_account.FirstRecord())
{
//retrieve the values. This method acts sort of like a business
//service in that there is an input property set and an output
//property set. The field values will be in the second property set
//passed in.
lbc_account.GetMultipleFieldValues(lPS_FieldNames,lPS_FieldValues);
}
//now set new values in the property set
lPS_FieldNames.SetProperty("Account Products", "All My Products");
lPS_FieldNames.SetProperty("Agreement Name", "Siebel Agreement");
lPS_FieldNames.SetProperty("Project Name", "Siebel Project #2");
lPS_FieldNames.SetProperty("Description", "This is the description");
lPS_FieldNames.SetProperty(“Name", "Joey Joe Joe Junior Shabbidoo");
New Methods
Continued In this example, the code creates lPS_FieldNames to hold the field names and
lPS_FieldValues to hold the field values.
After setting the value using the SetProperty method, invoke
ActivateMultipleFields and the Siebel application passes the property set in
as parameter.
After calling the ExecuteQuery method, invoke GetMultipleFieldValues to
get the field values. If you did not use GetMultipleFields and
ActivateMultipleFields, you would have to individually activate or get each of
the field values.
Notice the use of SetMultipleFieldValues here. If you did not use
SetMultipleFieldValues, you would have to individually set the field values.
View mode settings control the formulation of the SQL WHERE clause that the
Siebel application sends to the database by using team or position visibility to
limit the records available in the business component queried in the script.
Setting a query to AllView visibility mode gives the user access to all records,
which may be different than the view mode of the current view in the UI. For
example, a user may have SalesRep visibility on the UI whereas the script will
be giving the user All visibility. This would give the user access to records the
user might not need to access, or should not be able to access.
Setting view mode is especially important in an environment with mobile Web
client users. Mobile users have a subset of data in their local databases. If you
do not set the view mode correctly for limited visibility objects, unexpected
behavior can occur, such as resetting foreign keys. For example, the
application may set the Primary ID to No Match Row ID if a child record does
not exist on the local database. This update has the potential to synchronize
back up to the server, causing a data integrity problem.
To avoid this issue, use the GetViewMode method to determine the user’s
visibility so that you can apply the same view mode in the query executed by
the script.
eScript Example:
with (bcAcct)
{
SetViewMode(this.GetViewMode());
Siebel VB Example:
With bcAcct
.SetViewMode Me.GetViewMode
To assist the database engine in efficiently retrieving and sorting data, be sure
that search and sort specs reference indexed columns whenever possible.
Sorting or searching on non-indexed fields can have detrimental effects on
database performance, especially on large tables, as it produces table scans
and temporary tables in the SQL execution plan. This is true of search and sort
specifications that developers create in script, just as if they created them
using configuration.
For best performance, ensure that such specifications cover the key columns
of the desirable index, as well as cover them in the exact index sequence
order. This encourages the database engine to use the index and may prevent
unnecessary physical sorts in temporary tables.
If you do not specify a cursor mode when querying with Siebel eScript or
Siebel VB, the Siebel application uses the default cursor mode of
ForwardBackward. To support this cursor mode, the system creates a cache
to maintain the entire record set.
If you will traverse through the record set from FirstRecord using NextRecord
and will not return to a previous record, use ForwardOnly cursor mode. The
system will not need to create the cache, improving performance. This is
particularly true if you perform a look up or if you access a pick list.
Example:
bcAccount.ExecuteQuery(ForwardOnly);
When performing a query, always check that a record is returned through the
use of FirstRecord, NextRecord, or LastRecord methods, before attempting
to retrieve or set a field value for the record. Do this even if it seems
impossible that a record will not return.
Example:
bcContact.ClearToQuery();
bcContact.SetSearchSpec(“Id”, sContactId);
bcContact.ExecuteQuery(ForwardOnly);
//Check to see that a record was actually returned
//by examining the return of FirstRecord().
if (bcContact.FirstRecord())
{
//okay to perform data processing…
}
When you need to evaluate and compare a single expression with many
different possibilities, the fastest and most readable way of doing this is to
use switch (eScript) or select case (Siebel VB).
• It is more efficient because the expression is evaluated once, then
compared to different values.
• It is easier to read than a series of nested if…else if statements. Using
switch or select case statements can frequently compact multiple pages
of script into a single page.
When using switch or select case, be sure to test all conditions, not just the
most obvious ones. Logic errors can occur in code that does not consider all
possible conditions. Consider using default or case else to hold a default set
of behaviors that should occur if none of the stated conditions is met.
eScript Example:
Instead of Use
If(iNum == 1) switch(iNum)
sGrade = ‘A’; {
else case 1:
if(iNum ==2) sGrade = ‘A’;
sGrade = ‘B’; break;
else case 2:
if(iNum == 3) sGrade = ‘B’;
sGrade = ‘C’; break;
case 3:
sGrade = ‘C’;
}
if (ls_first == “first”)
{
……do something……
}
else if (ls_second == “second”)
{
…………do something else………
}
In the example above, the code evaluates two conditions: ls_first and
ls_second. Both evaluate to true, but the logic of only the first condition will
execute.
As with switch and select case, be sure to test all conditions, not just the
most obvious ones. Logic errors may occur in code if you do not consider all
possibilities.
Alternatively, you can store values in the List Of Values table or other
database tables and query for them at runtime. This is most appropriate
when there is only one dynamic value or a short list of values which you need
to query for in the script. If you have one value, or a short list that will fit
within one LOV entry, use the LookupValue function to retrieve the value.
Using LookupValue is especially important if you have implemented
Multilingual List of Values (MLOV).
If you need to store multiple LOV values with a common LOV Type, the script
can query directly on the List Of Values business component. In the following
example, the LOV values are queried from the List Of Values buscomp, then
concatenated together to form a query filter string.
Example:
var statusList;
var moreRecords;
var boLOV;
var bcLOV;
Always use logical constants where they are available. It makes your code
easier to read and easier to upgrade. Literal values are prone to upgrade
problems as Siebel applications could change the behavior behind a literal
value.
Example:
bc.NewRecord(1);
Most likely, future developers reading this script will have to look up what 1
means. Also, if Siebel Systems were to change what this literal value does in
the NewRecord method in the C++ class, this code may not behave as
expected. Using the logical constant alleviates both of these issues. The
above line of code is better implemented as:
bc.NewRecord(NewAfter);
These are the most commonly used logical constants and their literal values.
Type Logical Constant Value
CursorMode: ForwardBackward 0 (default)
ForwardOnly 1
ViewMode: SalesRep View 0
ManagerView 1
PersonalView 2
AllView 3
OrganizationView 5
ContactView 6
GroupView 7
CatalogView 8
SubOrganizationView 9
NewRecordLocation: NewBefore 0 (default)
NewAfter 1
NewBeforeCopy 2
NewAfterCopy 3
There are two general objections to using Exit Sub or Exit Function in Siebel
VB.
First, it is difficult to follow the flow of a script with multiple exit points. It is
easier to follow and maintain a script with one exit point.
Second, multiple exit points increase the chance of memory leaks from not
properly destroying objects. When a script exits abruptly, object references
are not released unless explicitly written that way. In methods where there
are many exit points, developers have to duplicate this code in many
locations.
The GotoView statement does not immediately exit a script and navigate to
the specified view. Rather, the script holds the statement aside until the
entire script executes. Finally, as the last statement, the script executes the
method regardless of where it appeared in the script. For example, if the
first statement in a script is a GotoView statement, it will not execute until
all other code executes. Therefore, it is good practice to place GotoView
statements at the end of a script, to represent what actually happens.
DeleteRecord implicitly moves the record pointer to the next record in the
record set. A call to NextRecord after DeleteRecord causes the record
pointer to move twice. This means that the Siebel application skips a record
in the result set. If it is deleting records within a loop, the Siebel application
skips every other record.
The following example illustrates the recommended approach for deleting
records within a loop.
Siebel VB
While(BC.FirstRecord <> 0)
BC.DeleteRecord
Wend