Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.



Published on


  • Be the first to comment

  • Be the first to like this


  1. 1. Access Tutorial 15: Advanced Triggers15.1 Introduction: Pulling it all How do I create an unbound combo box? together Can I implement the search capability usingIn this tutorial, you will bring together several of the Visual Basic?skills you have learned in previous tutorials to imple-ment some sophisticated triggers. 15.3 Tutorial exercises15.2 Learning objectives 15.3.1 Using a macro to run VBA code There a some things that cannot be done using the How do I run VBA code using a macro? Access macro language. If the feature you wish to How do I use the value in one field to implement is critical to your application, then you automatically suggest a value for a different must implement it using VBA. However, since it is field? possible to call a VBA function from within a macro, How do I change the table or query a form is you do not have to abandon the macro language bound to once the form is already created? completely. What is the After Update event? How is it In this section, you are going to execute the Param- used? eterTest subroutine you created in Section 12.3.6 from within a macro. Since the RunCode action of How do I provide a search capability for my the Access macro language can only be used to exe- forms?© Michael Brydon ( update: 25-Aug-1997 Home Previous 1 o f 33 Next
  2. 2. 15. Advanced Triggers Tutorial exercisescute functions (not subroutines) you must do one of this function calls thetwo things before you create the macro: ParameterTest subroutine1. Convert ParameterTest to a function — you do ParameterTest intStart, intStop this simply by changing the Sub at the start of the ParameterTestWrapper = True return a value procedure to Function. End Function2. Create a new function that executes Parame- • Call the function, as shown in Figure 15.1. terTest and call the function from the macro. Creating a wrapper Note that the return value of the function isSince the second alternative is slightly more interest- declared as an integer, but the actual assign-ing, it is the one we will use. ment statement is ParameterTestWrap- • Open your basTesting module from per = True. This is because in Access/ Tutorial 12. VBA, the constants True and False are • Create a new function called ParameterTest- defined as integers (-1 and 0 respectively). Wrapper defined as follows: Using the RunCode action Function • Leave the module open (you may have to resize ParameterTestWrapper(intStart As and/or move the debug window) and create a Integer, intStop As Integer) As new macro called mcrRunCodeTest. Integer Home Previous 2 o f 33 Next
  3. 3. 15. Advanced Triggers Tutorial exercises FIGURE 15.1: Create a function that calls the ParameterTest subroutine. the ParameterTest Create a function to call subroutine. Since ParameterTest invoke the function (do notto Use the Print statement forget does not return a value, its the parameters). arguments are not in brackets. The return value of ParameterTestWrapper() is True, so this is printed when the function ends. Home Previous 3 o f 33 Next
  4. 4. 15. Advanced Triggers Tutorial exercises • Add the RunCode action and use the expression • Select Run Start to execute the macro as builder to select the correct function to execute, shown in Figure 15.3. as shown in Figure 15.2. 15.3.2 Using activity information to The expression builder includes two parame- determine the number of credits ter place holders (intStart and In this section, you will create triggers attached to the intStop) in the function name. These After Update event of bound controls. are to remind you that you must pass two parameters to the ParameterTestWrap- Scenario per() function. If you leave the place holders Assume that each type of course activity is generally where they are, the macro will fail because associated with a specific number of credits, as Access has not idea what intStart shown below: and intStop refer to. Activity Credits • Replace the parameter place holders with two lecture 3.0 numeric parameters (e.g. 3 and 6). Note that in lab 3.0 general, the parameters could be field names or tutorial 1.0 any other references to Access objects contain- seminar 6.0 ing (in this case) integers. Home Previous 4 o f 33 Next
  5. 5. 15. Advanced Triggers Tutorial exercises FIGURE 15.2: Use the expression builder to select the function to execute. action to the macro. Add a RunCode Note the intStart and intStop parameter place holders. These must be replaced with expressions that Access understands. downthe expression builder to drill in Use to the user-defined functions your database file. Home Previous 5 o f 33 Next
  6. 6. 15. Advanced Triggers Tutorial exercises Assume as well that the number of credits for a par- FIGURE 15.3: Execute the RunCode macro. ticular type of course is not cast in stone. As such, the numbers given above are merely “default” val- ues. You want to use the default credit values when you create a new course or modify an existing course. However, the user may override this default if neces- sary for a particular course. The basic requirement is illustrated in Figure 15.4. Designing the trigger Based on the foregoing, the answer to the “what” parameter place Replace the question is the following: 1. Look up the default number of credits associated holders. with the course activity showing in the form’s Activity field. the toolRun toStart (or press the ! icon in Select bar) execute the macro. 2. Copy this number into the Courses.Credits field. Home Previous 6 o f 33 Next
  7. 7. 15. Advanced Triggers Tutorial exercises FIGURE 15.4: Inserting a default value into a new record. Create a new record for a lecture-based of creditsmacro to find the default number Create a and copy the value it into the course: COMM 437: Database Technology Credits field. Select “Lecture” from the list of list of course activities created in Tutorial 8. Since this is a new record, the default value of Credits (like any numeric field) is zero. You want to use the information you just specified in the macrothe Activityvalue in the the Once executes. The field is updated, Activity field to automatically Credits field can be changed by the look up the correct default number of user. credits for a lecture course and insert it in the Credits field. Home Previous 7 o f 33 Next
  8. 8. 15. Advanced Triggers Tutorial exercisesThere are several possible answers to the “when” • Ensure that you have a courses form (e.g., frm-question (although some are better than others). For Courses) and that the form has a combo box forexample: the Activity field. You may wish to order the1. When the user enters the Credits field (the On fields such that Activity precedes Credits in Enter event for Credits) — The problem with the tab order (as shown in Figure 15.4). this choice is that the user could modify the If your move fields around, remember to course’s activity without moving the focus to the adjust the tab order accordingly (recall Activity field. In such a case, the trigger would Section 8.3.4). not execute.2. When the user changes the Activity field (the Looking up the default value After Update event for Activity) — This choice As you discovered in Section 14.3.5, Access has a guarantees that whenever the value of Activ- DLookUp() function that allows you to go to the ity is changed, the default value will be copied Activities table and find the value of Credits into the Credits field. As such, it is a better for a particular value of Activity. A different choice. approach is to join the Activities table with the15.3.2.3 Preliminary activities Courses table in a query so that the default value of • Modify the Activities table to include a single- credits is always available in the form. This is the precision numeric field called Credits. Add the approach we will use here. values shown in the table in Section Home Previous 8 o f 33 Next
  9. 9. 15. Advanced Triggers Tutorial exercises • Ensure you have a relationship (in the main rela- FIGURE 15.5: Use a join to make the default tionship window) between Courses.Activity value available. and Activities.Activity. • Create a new query called qryCoursesAnd- Credits based on the Courses and Activi- ties tables (see Figure 15.5). Notice that you have two credits fields: Courses.Credits (the actual number of credits for the course) and Activi- ties.Credits (the “default” or “suggested” number of credits based on the value of Activity). Access uses the table name.field name notation whenever a query contains more than one field with the same name.Since you already have forms based on theCourses table that expect a field called Credits(rather than one called Courses.Credits), it is a Home Previous 9 o f 33 Next
  10. 10. 15. Advanced Triggers Tutorial exercisesgood idea to rename the Activities.Credits FIGURE 15.6: Rename one of the Credits fields.field in the query. You do this by creating a calculatedfield. • Rename Activities.Credits to Default- Credits as shown in Figure 15.6. Note that this eliminates the need for the table name.field name notation. Changing the Record Source of the formRather than create a new form based on the qry-CoursesAndCredits query, you can modify theRecord Source property of the existing frmCoursesform so it is bound to the query rather than theCourses table. • Bring up the property sheet for the frmCourses form and change the Record Source property to qryCoursesAndCredits as shown in Figure 15.7. table to DefaultCredits.Activities Rename Credits form the Home Previous 10 o f 33 Next
  11. 11. 15. Advanced Triggers Tutorial exercises The advantage of using a join query in this manner is FIGURE 15.7: Change the Record Source that DefaultCredits is now available for use property of an existing form. within the form and within any macros or VBA mod- changeup the form’sSource property. Bring its Record property list and ules that run when the form is open. Creating the SetValue macro The SetValue macro you require here is extremely simple once you have DefaultCredits available within the scope of the form. • Create the mcrCourses.SetCredits macro as shown in Figure 15.8. Attaching a procedure to the After Update event The On Click event of a button is fairly simple to understand: the event occurs when the button is clicked. The events associated with non-button objects operate in exactly the same way. For exam- ple, the After Update event for controls (text box, The field list now contains all the fields in the new query. combo box, check box, etc.) occurs when the value Home Previous 11 o f 33 Next
  12. 12. 15. Advanced Triggers Tutorial exercises • Attach the mcrCourses.SetCredits macro to FIGURE 15.8: Create the SetValue macro. the After Update event of the Activity field. • Verify that the trigger works properly. and a named macro called SetCredits. Create a macro group called mcrCourses 15.3.3 Use an unbound combo box to automate search As mentioned in Tutorial 8, a combo box has no intrinsic search capability. However, the idea of scan- ning a short list of key values, selecting a value, and having all the information associated with that record pop on to the screen is so basic that in Access ver- sion 7.0 and above, this capability is included in the combo box wizard. In this tutorial, we will look at a or simplyuse the builder to set the arguments You can type in the names of the fields. couple of different means of creating a combo boxes for search from scratch.of the control is changed by the user. As a result, the Manual search in AccessAfter Update event is often used to trigger data verifi- To see how Access searches for records, do the fol-cation procedures and “auto-fill” procedures like the lowing:one you are creating here. • Open your frmDepartments form. Home Previous 12 o f 33 Next
  13. 13. 15. Advanced Triggers Tutorial exercises • Move to the field on which you want to search • Set the Enabled property of DeptCode to No (the (e.g., DeptCode); user should never be able to change the key val- • Select Edit Find (or press Control-F); ues of existing records). • Fill out the search dialog box as shown in Creating the unbound combo box Figure 15.9. The key thing to remember about the combo boxIn the dialog box, you specify what to search for used to specify the search criterion is that it has(usually a key value) and specify how Access should nothing to do with the other fields or the underlyingconduct its search. When you press Find First, table. As such, it should be unbound.Access finds the first record that matches your • Create an unbound combo box in the formsearch value and makes it the current record (note header, as shown in Figure 15.10.that if you are searching on a key field, the first • Change the Name property of the combo box tomatching record is also the only matching record). cboDeptCode. Preliminaries • The resulting combo box should resemble thatTo make this more interesting, assume that the frm- shown in Figure 15.11.Departments form is for viewing editing existing When you create an unbound combo box,departmental information (rather than adding new Access gives it a default name (e.g.,departments). To enforce this limitation, do the fol- Combo5). You should do is change this tolowing: something more descriptive (e.g., cboDept- • Set the form’s Allow Additions property to No. Home Previous 13 o f 33 Next
  14. 14. 15. Advanced Triggers Tutorial exercises FIGURE 15.9: Search for a record using the “find” dialog box. the field you wishtoto Move the cursor search and invoke the search box using Control-F. and setthe value you wish to find Enter the other search parameters as required. Limit the search to the current field (i.e., the field with the focus when the search box was opened). (or only) record thatmove to the first Press Find First to matches the search condition. Home Previous 14 o f 33 Next
  15. 15. 15. Advanced Triggers Tutorial exercises FIGURE 15.10: Create an unbound combo box. down themake roomfor the detail Drag to separator in the form header selecting the combocombo boxand Create an unbound box tool by clicking in the header area. Use the wizard in the usual way to get a list of valid DeptCode values and descriptions. The bound column for the combo box should be DeptCode. its value has to bebox is unbound, Since the combo stored for later use rather than stored in a field. Home Previous 15 o f 33 Next
  16. 16. 15. Advanced Triggers Tutorial exercises Automating the search procedure FIGURE 15.11: An unbound combo box. using a macro When we implement search functionality with a combo box, only two things are different from the manual search in Figure 15.9: 1. the search dialog box does not show up, and 2. the user selects the search value from the combo box rather than typing it in. The basic sequence of actions, however, remains Although the DeptCode column has been the same. As a result, the answer to the “what” ques- hidden, it is the “bound” column. As a result, the value of the combo box as it appears here tion is the following: is “COMM”, not “Commerce and ...” 1. Move the cursor to the DeptCode field (this allows the “Search Only Current Field” option to Code). The advantage of the prefix cbo is be used, thereby drastically cutting the search that it allows you to differentiate between the time). bound field DeptCode and the unbound 2. Invoke the search feature using the current value combo box. of cboDeptCode as the search value. Home Previous 16 o f 33 Next
  17. 17. 15. Advanced Triggers Tutorial exercises3. Move the cursor back to cboDeptCode or some FIGURE 15.13: Fill in the arguments for the other field. FindRecord action.The only problem with this procedure is that theDeptCode text box is disabled. As a result, you mustinclude an extra step at the beginning of the macro mcrSearch.FindDepartment. Create a named macro calledto set its Enabled property to Yes and another at theend of the macro to return it to its original state. • Create a new macro called mcrSearch.Find- Department. • Use the SetValue action to set the Dept- Code.Enabled property to Yes. This can be done using the expression builder, as shown in Figure 15.12. • Use the GotoControl action to move the cursor Since Value is the default to the DeptCode text box. Note that this action property, its use will fail if the destination control is disabled. is optional. • Use the FindRecord action to implement the search as shown in Figure 15.13. equalsthe action arguments. Dothe combo box. Enter sign before the name of not forget the Home Previous 17 o f 33 Next
  18. 18. 15. Advanced Triggers Tutorial exercises FIGURE 15.12: Use the builder to specify the name of the property to set. expressionItem argument, down To set the builder to drill use the to the correct form. The middle pane shows all the objects on the form including labels and buttons (hence the need for a good naming convention). (cboDeptCode) from thebox Select the unbound combo middle pane. A list of properties for the selected object is displayed in the pane on the right. Home Previous 18 o f 33 Next
  19. 19. 15. Advanced Triggers Tutorial exercises Access interprets any text in the Find What 15.3.4 Using Visual Basic code instead of argument as a literal string (i.e., quotation a macro marks would not be required to find COMM). To Instead of attaching a macro to the After Update use an expression (including the contents of a event, you can attach a VBA procedure. The VBA control) in the Find What argument, you must procedure is much shorter than its macro counter- precede it with an equals sign (e.g., part: =[cboDeptCode]. 1. a copy (clone) of the recordset underlying the • You cannot disable a control if it has the focus. form is created, Therefore, include another GotoControl action 2. the FindFirst method of this recordset is used to move the cursor to cboDeptCode before set- to find the record of interest. ting DeptCode.Enabled = No. 3. the “bookmark” property of the clone is used to • Attach the macro mcrSearch.FindDepart- move to the corresponding bookmark for the ment to the After Update event of the cboDept- form. Code combo box. To create a VBA search procedure, do the following: • Test the search feature. • Change the After Update event of cboDeptCode to “Event Procedure”. • Press the builder ( ) to create a VBA subrou- tine. Home Previous 19 o f 33 Next
  20. 20. 15. Advanced Triggers Application to the assignment • Enter the two lines of code below, as shown in a non-human-readable data type and therefore is Figure 15.14. not of much use unless it is used in the manner Me.RecordsetClone.FindFirst shown here. Setting the Bookmark property of a “DeptCode = ‘” cboDeptCode “” record makes the record with that bookmark the Me.Bookmark = current record. In the example above, the book- Me.RecordsetClone.Bookmark mark of the records underlying the form is set toThis program consists of a number of interesting ele- equal the bookmark of the clone. Since the clonements: had its bookmark set by the search procedure, • The property Me refers to the current form. You this is equivalent to searching the recordset can use the forms actual name, but Me is much underlying the form. faster to type. • A form’s RecordsetClone property provides a 15.4 Application to the assignment means of referencing a copy of the forms under- lying recordset. 15.4.1 Triggers to help the user • The FindFirst method is straightforward. It • Create a trigger on your order form that sets the acts, in this case, on the clone. actual selling price of a product to its default • Every recordset has a bookmark property that price. This allows the user to accept the default uniquely identifies each record. A bookmark is price or enter a new price for that particular trans- like a “record number”, except that it is stored as action (e.g., the item could be damaged). You will Home Previous 20 o f 33 Next
  21. 21. 15. Advanced Triggers Application to the assignment FIGURE 15.14: Implement the search feature using a short VBA procedure. referencethe After Update event to Change an event procedure. editor.the builder button to invoke the VBA Press Access automatically names the subroutine. Enter the two lines of code. Home Previous 21 o f 33 Next
  22. 22. 15. Advanced Triggers Application to the assignment have to think carefully about which event to Section 10.4). The problem is updating the Back- attach this macro to. Orders table itself because two different situations • Create a trigger on your order form that calcu- have to be considered: lates a suggested quantity to ship and copies this 1. A record for the particular customer-product value into the quantity to ship field. The sug- combination exists in the BackOrders table -- gested value must take into account the amount If a backorder record exists for a particular cus- ordered by the customer, any outstanding backo- tomer and a particular product, the quantity field rders for that item by that customer, and the cur- of the record can be added-to or subtracted-from rent quantity on hand (you cannot ship what you as backorders are created and filled. do not have). The user should be able to override 2. A customer-product record does not exist in this suggested value. (Hint: use the MinValue() the BackOrders table -- If the particular cus- function you created in Section 12.5.) tomer has never had a backorder for the product • Provide you customer and products forms with in question, then there is no record in the Back- search capability. Orders table to update. If you attempt to update a nonexistent record, you will get an error.15.4.2 Updating the BackOrders table What is required, therefore, is a means of determin-Once a sales order is entered into the order form, it ing whether a record already exists for a particularis a simple matter to calculate the amount of each customer-product combination. If a record doesproduct that should be backordered (you did this in exist, then it has to be updated; if a record does not Home Previous 22 o f 33 Next
  23. 23. 15. Advanced Triggers Application to the assignmentexist, then one has to be created. This is simple (see Section to review renamingenough to talk about, but more difficult to implement fields in queries).in VBA. As a result, you are being provided with ashortcut function called UpdateBackOrders() Note that if the backordered quantity is positive,that implements this logic. items are backordered. If the backordered quantity is negative, backorders are being filled. If the backor-The requirements for using the UpdateBackO- dered quantity is zero, no change is required andrders() function are outlined in the following sec- these records should no be included in the results oftions: the query. Create the pqryItemsToBackOrder Import the shortcut function query Import the Visual Basic for Applications (VBA) mod-If you have not already done so, create the pqry- ule containing the code for theItemsToBackOrder query described in UpdateBackOrders() function. This module isSection 10.4. The UpdateBackOrders() proce- contained in an Access database calleddure sets the parameter for the query and then cre- BOSC_Vx.mdb that you can download from theates a recordset based on the results. course home page. If you did not use the field names OrderID, • BOSC_V2.mdb is for those running Access ver- and ProductID in your tables, you must use sion 2.0. To import the module, select File the calculated field syntax to rename them Home Previous 23 o f 33 Next
  24. 24. 15. Advanced Triggers Application to the assignment Import, choose BOSC_V2.mdb, and select Mod- ers, and Products. If any of your tables or fields ule as the object type to import. are named differently, an error occurs. To eliminate • BOSC_V7.mdb is for those running Access ver- these errors, you can do one of two of things: sion 7.0 or higher. To import the module, select 1. Edit the VBA code. Use the search-and-replace File Get External Data Import, choose feature of the module editor to replace all BOSC_V7.mdb, and select Module as the object instances of field names in the supplied proce- type to import. dures with your own field names. This is the rec- Use the function in your application ommended approach, although you need an adequate understanding of how the code worksThe general syntax of the function call is: in order to know which names to change.UpdateBackOrders(OrderID, CustomerID). 2. Change the field names in your tables (and allThe OrderID and CustomerID are arguments and queries and forms that reference these fieldthey both must be of the type Long Integer. If this names). This approach is not recommended.function is called properly, it will update all the backo-rdered items returned by the parameter query. 15.4.3 Understanding the15.4.2.4 Modifying the UpdateBackOrders() UpdateBackOrders() function function The flowchart for the UpdateBackOrders() func-The UpdateBackOrders() function looks for spe- tion is shown in Figure 15.15. This function repeat-cific fields in three tables: BackOrders, Custom- edly calls a subroutine, BackOrderItem, which Home Previous 24 o f 33 Next
  25. 25. 15. Advanced Triggers Application to the assignmentupdates or adds the individual items to the BackO- FIGURE 15.15: Flowchart forrders table. The flowchart for the BackOrderItem UpdateBackOrders().subroutine is shown in Figure 15.16.There are easier and more efficient ways of imple- startmenting routines to update the BackOrders table.Although some amount of VBA code is virtually inev- run pqryItemsToBackOrder to get list of items to backorderitable, a great deal of programming can be elimi-nated by using parameter queries and actionqueries. Since queries run faster than code in is yesAccess, the more code you replace with queries, the the list error message stop empty?better. no To get full marks for the backorders aspect of the assignment, you have to create a more do until end of list elegant alternative to the shortcut supplied here. call BackOrderItems (CustID,ProductID,Qty) stop Home Previous 25 o f 33 Next
  26. 26. 15. Advanced Triggers Application to the assignment FIGURE 15.16: Flowchart for the BackOrderItem subroutine. start search BackOrders table for matching CustID ProductID yes yes check Products table to ensure valid ProductID found? update Qty stop no no check Customer table to valid? error message stop ensure valid CustID yes no add new record with CustID, ProductID Qty valid? error message stop stop Home Previous 26 o f 33 Next
  27. 27. 15. Advanced Triggers Application to the assignment15.4.4 Annotated source code for the MsgBox “Back order cannot be processed: backorders shortcut module. order contains no items” Exit SubIn the following sections, the two procedures in the End Ifshortcut module are examined. In each case, the Do Until rsBOItems.EOFcode for the procedure is presented followed by Call BackOrderItem(lngCustID,comments on specific lines of code. rsBOItems!ProductID, rsBOItems!Qty) The UpdateBackOrders() function rsBOItems.MoveNextFunction UpdateBackOrders(ByVal Loop lngOrdID As Long, ByVal lngCustID As rsBOItems.Close Long) End FunctionSet dbCurr = CurrentDb Explanation of theDim rsBOItems As Recordset UpdateBackOrders() functiondbCurr.QueryDefs!pqryItemsToBackOrder. Parameters!pOrderID = lngOrdID Function UpdateBackOrders(ByVal lngOr-Set rsBOItems = dID As Long, ByVal lngCustID As Long) — dbCurr.QueryDefs!pqryItemsToBackOrder This statement declares the function and its parame- .OpenRecordset() ters. Each item in the parameter list contains threeIf rsBOItems.RecordCount = 0 Then elements: ByVal or ByRef (optional), the variables name, and the variables type (optional). The ByVal Home Previous 27 o f 33 Next
  28. 28. 15. Advanced Triggers Application to the assignmentkeyword simply means that a copy of the variables Dim rsBOItems As Recordset — In this decla-value is passed the subroutine, not the variable ration statement, a pointer to a Recordset object isitself. As a result, variables passed by value cannot declared. This recordset contains a list of all thebe changed by the sub-procedure. In contrast, if a items to add to the BackOrders table.variable is passed by reference (the default), its dbCurr.QueryDefs!pqryItemsToBackOrdervalue can be changed by the sub-procedure. .Parameters!pOrderID = lngOrdID — ThisSet dbCurr = CurrentDb — Declaring a vari- one is a bit tricky: the current database (dbCurr)able and setting it to be equal to something are dis- contains a collection of objects called QueryDefstinct activities. In this case, the variable dbCurr (these are what you create when you use the QBE(which is declared in the declarations section) is set query designer). Within the collection of QueryDefs,to point to a database object. Note that the database there is one called pqryItemsToBackOrderobject is not created, it already exists. (which you created in Section is a function supported in Access ver- Within every QueryDef, there is a collection of zerosion 7.0 and higher that returns a reference to the or more Parameters. In this case, there is one calledcurrent database. In Access version 2.0, this function pOrderID and this sets the value of the parameterdoes not exist and thus the current database must to the value of the variable lngOrderID (which wasbe found by starting at the top level object in the passed to the function as a parameter).Access DAO hierarchy, as discussed in Set rsBOItems = dbCurr.QueryDefs!pqry-Section 14.3.1. ItemsToBackOrder.OpenRecordset() — Here Home Previous 28 o f 33 Next
  29. 29. 15. Advanced Triggers Application to the assignmentis another set statement. In this one, the variable MsgBox “Back order cannot be processed:rsBOItems is set to point at a recordset object. order contains no items” — The MsgBoxUnlike the current database object above, however, statement pops up a standard message box with anthis recordset does not yet exist and must be created Okay button in the running the pqryItemsToBackOrder parame- Exit Sub — If this line is reached, the list containster query. no items. As such, there is no need to go any furtherOpenRecordset is a method that is defined for in this subroutine.objects of type TableDef or QueryDef that creates an End If — The syntax for If… Then… Else… state-image of the data in the table or query. Since the ments requires an End If statement at the end ofquery in question is a parameter query, and since the the conditional code. That is, everything between theparameter query is set in the previous statement, the If and the End If executes if the condition is true;resulting recordset consists of a list of backordered otherwise, the whole block of code is ignored.items with an order number equal to the value of Do Until rsBOItems.EOF — The EOF propertypOrderID. of a recordset is set to true when the “end of file” isIf rsBOItems.RecordCount = 0 Then — The encountered.only thing you need to know at this point about the Call BackOrderItem(lngCustID, rsBOI-RecordCount property of a recordset is that it returns tems!ProductID, rsBOItems!Qty) — A sub-zero if the recordset is empty. routine is used to increase the modularity and Home Previous 29 o f 33 Next
  30. 30. 15. Advanced Triggers Application to the assignmentreadability of this function. Note the way in which the The BackOrderItem() subroutinecurrent values of ProductID and Qty from the Sub BackOrderItem(ByVal lngCustID AsrsBOItems Recordset are accessed. Long, ByVal strProdID As String, ByVal intQty As Integer)rsBOItems.MoveNext — MoveNext is a method Set dbCurr = CurrentDbdefined for recordset objects. If this is forgotten, the Dim strSearch As StringEOF condition will never be reached and an infinite Dim rsBackOrders As Recordsetloop will be created. In VBA, the Escape key is usu- Set rsBackOrders =ally sufficient to stop an infinite loop. dbCurr.OpenRecordset(“BackOrders”,Loop — All Do While/Do Until loops must end dbOpenDynaset)with the Loop statement. strSearch = “CustID = “ lngCustID “rsBOItems.Close — When you create a new AND ProductID = strProdID “”object (such as a Recordset using the Open- rsBackOrders.FindFirst strSearchRecordset method), you should close it before exit- If rsBackOrders.NoMatch Thening the procedure. Note that you do not close Dim rsCustomers As RecordsetdbCurr because you did not open it. Set rsCustomers = dbCurr.OpenRecordset(“Customers”,End Function — All functions/subroutines need dbOpenDynaset)an End Function/End Sub statement. strSearch = “CustID = “ lngCustID rsCustomers.FindFirst strSearch Home Previous 30 o f 33 Next
  31. 31. 15. Advanced Triggers Application to the assignmentIf rsCustomers.NoMatch Then rsBackOrders!Qty = intQtyMsgBox “An invalid Customer ID number rsBackOrders.Update has been passed to BackOrderItem” ElseExit Sub rsBackOrders.EditEnd If rsBackOrders!Qty = rsBackOrders!Qty +Dim rsProducts As Recordset intQtySet rsProducts = rsBackOrders.Update dbCurr.OpenRecordset(“Products”, End If dbOpenDynaset) End SubstrSearch = “ProductID = strProdID Explanation of the BackOrderItem() “” subroutinersProducts.FindFirst strSearchIf rsProducts.NoMatch Then Since many aspects of the language are covered inMsgBox “An invalid Product ID number the previous subroutine, only those that are unique has been passed to BackOrderItem” to this subroutine are explained.Exit Sub Set rsBackOrders = dbCurr.OpenRecord-End If set(“BackOrders”, dbOpenDynaset) — ThersBackOrders.AddNew OpenRecordset method used here is the onersBackOrders!CustID = lngCustID defined for a Database object. The most importantrsBackOrders!ProductID = strProdID argument is the source of the records, which can be Home Previous 31 o f 33 Next
  32. 32. 15. Advanced Triggers Application to the assignmenta table name, a query name, or an SQL statement. do this, single quotes are used within the searchThe dbOpenDynaset argument is a predefined con- string.stant that tells Access to open the recordset as a rsBackOrders.FindFirst strSearch —dynaset. You dont need to know much about this FindFirst is a method defined for Recordsetexcept that the format of these predefined constants objects that finds the first record that meets the crite-is different between Access version 2.0 and version ria specified in the methods argument. Its argument7.0 and higher. In version 2.0, constants are of the is the text string stored in strSearch.form: DB_OPEN_DYNASET. If rsBackOrders.NoMatch Then — ThestrSearch = “CustID = ” lngCustID “ NoMatch property should always be checked afterAND ProductID = ’” strProdID “” — searching a record set. Since it is a Boolean variableA string variable has been used to break the search (True / False) it can be used without an comparisonprocess into two steps. First, the search string is operator.constructed; then the string is used as the parameter rsBackOrders.AddNew — Before information canfor the FindFirst method. The only tricky part here be added to a table, a new blank record must be cre-is that lngCustID is a long integer and strProdID ated. The AddNew method creates a new emptyis a string. The difference is that the value of str- record, makes it the active record, and enables it forProdID has to be enclosed in quotation marks when editing.the parameter is passed to the FindFirst method. To Home Previous 32 o f 33 Next
  33. 33. 15. Advanced Triggers Application to the assignmentrsBackOrders!CustID = lngCustID — Notethe syntax for changing a variable’s value. In thiscase, the null value of the new empty record isreplaced with the value of a variable passed to thesubroutine.rsBackOrders.Update — After any changes aremade to a record, the Update method must beinvoked to “commit” the changes. The AddNew /Edit and Update methods are like bookendsaround changes made to records.rsBackOrders.Edit — The Edit method allowsthe values in a record to be changed. Note that thesechanges are not saved to the underlying table untilthe Update method is used. Home Previous 33 o f 33 Next