Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 58 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
58
Dung lượng
1,35 MB
Nội dung
CHAPTER 3 USING DATA MACROS 58 Exploring the Macro Editor You’ll be creating several more data macros, but before you do that, I want to explain some of the features of the Macro Editor. As you’ve noticed, you don’t write code; instead, you design a macro by adding actions and filling in the appropriate parameters. The Action Catalog, shown in Figure 3-9, provides a good overview of the available actions. Figure 3-9. The Action Catalog There are three types of actions: Program Flow, Data Blocks, and Data Actions. The Comment action, which you have already used, simply adds a line of text to explain something about the macro. You’ll use the Group and If actions later. The Group action allows you put a set of actions in a group, which can then be collapsed. This is roughly equivalent to the #region blocks in .NET code. The If action lets you add conditional logic in your macro. Understanding Data Blocks Accessing and updating data is always done inside a data block. When you add a data block action to a macro, the editor indents the block and highlights that area of the macro. It does this to help you keep track of the scope of that block. CHAPTER 3 USING DATA MACROS 59 For example, you used an EditRecord action, which is a data block action. You then added a SetField action to update a specific field of that record. The EditRecord action defines the record that is to be updated. The SetField action has to be inside the scope of the EditRecord action. If you were to place them outside of that scope, the Macro Editor would not know which record to update. The LookupRecord action works the same way. It looks up a single record. You can only access fields from that record while inside the scope of that data block. Likewise, you can only edit that record while inside that data block. That’s why the EditRecord action is inside the scope of the LookupRecord action. There are two other data block actions. The CreateRecord is used when you want to insert a new record. You add SetField actions inside this data block to specify the field values. The ForEachRecord action works like the LookupRecord action, except that it allows for multiple rows to be returned. You can then process each one in a for-next loop. Using Aliases An alias is used to name and then reference a data block. For example, the LookupRecord action was assigned an alias. The EditRecord action uses the same alias so the Macro Editor knows to update the record that was just returned by the LookupRecord action. Using Default Aliases The Macro Editor does its best to avoid the need for you to deal with aliases. The default alias that the macro editor assigns is the table name. In most cases you can ignore the Alias field, as you did in the macro that you just implemented. If you need to work with two records from the same table, for example, the default alias would be ambiguous. In this case, you’ll need to change the default alias for at least one the records. For those times that you need to specify an alias, you should understand how they work. First, I’ll explain how the default aliases work. In a data macro, the macro keeps track of the records that are being used. These records are referred to as data contexts. Initially, a macro is executed on behalf of a record that is about to be or has been modified. A data context is added to the macro for this record, and it’s given an alias using the table name. In your macro this was the Loan table, and you access its fields by putting “Loan.” in front of the field name. Whenever you add one of the data block actions (CreateRecord, LookupRecord, or ForEachRecord – EditRecord is a special case, which I’ll explain later), a new data context is added, and its default alias is determined by the table name. The LookupRecord action added a new data context with the InventoryItem alias. So inside the LookupRecord data block, there are now two data contexts, and their aliases are Loan and InventoryItem. The default data context is the last one to be added to the macro. Think of this like a stack. Initially the Loan data context was added. It’s on the top of the stack and is the default data context. When the LookupRecord action is executed, it adds the InventoryItem data context on top of the Loan data context. Inside the LookupRecord data block, the InventoryItem data context is the default context; it’s the last one that was added. Once the macro exits this data block, the InventoryItem data context is popped off the stack and the Loan data context is now the default. The Macro Editor will show the default in the Alias field, which is based on the name of the table. If you don’t change it, when you tab off that field, the Macro Editor changes it to an empty field. This signifies that the default alias is being used. CHAPTER 3 USING DATA MACROS 60 Using the EditRecord Action Unlike the other data block actions, the EditRecord action does not create a data context. Rather, it must be assigned one to use, which is done by entering the appropriate alias. If no alias is supplied, it will use the default data context. Since we’re inside the LookupRecord data block, the InventoryItem data context is used. If you were to add the EditRecord outside of the LookupRecord data block, the default data context would be the initial Loan record. As you might have already guessed, using default alias and data contexts can leave room for error. It is also a little more difficult for someone else to understand how the macro is supposed to work. For these reasons, I recommend that you always explicitly supply an alias. You can use the default name, when appropriate, but you’ll need to enter it in the field so the editor doesn’t display a blank value. Figure 3-10 shows your first macro with explicit aliases. Figure 3-10. The macro updated with explicit alias references When to Use an Alias There are times when you need to define an alias instead of using the default alias. For example, if you’re writing a macro for the Loan table. The default data context is given the alias Loan. Now suppose you wanted to look up the loan for the last time this item was checked out. You would add a LookupRecord action and the appropriate expression for the Where Condition. You would now have two records, both of which are from the Loan table. To avoid ambiguity, you would need to specify a different alias, such as PriorLoan. In subsequent expressions, you would specify Loan for the current record and PriorLoan for the previous loan. Using Data Actions The last section of the Action Catalog lists the available data actions. I will demonstrate many of these in the remainder of this chapter. Some of these are only available in certain situations. For example, SetField can only be used inside of an EditRecord or CreateRecord data block. The Add New Action dropdown list in the Macro Editor will list the subset of actions that are allowed based on the context. CHAPTER 3 USING DATA MACROS 61 Navigating the Macro Editor After you have added actions to your macro, the Macro Editor allows you rearrange them. Figure 3-11 shows these editing controls. Figure 3-11. The Macro Editor controls When you select an action, there is a minus “-” button at the top left, next to the action name. Collapsing actions can make it easier to read your macro, especially with more complex macros. If the action is already collapsed, there with be a plus “+” button instead, which will expand the action. At the top-right of the action there are green up and down arrows. Use these to change the order of the actions. If you select a data block action such as LookupRecord, the entire block will be moved. There is also an “X” button at the far top-right; use this to remove the action. To add a new action, use one of the Add New Action dropdown lists. These are only available in a few locations. Generally there is one for each indention level. After adding the action, use the green arrows to move it to the correct location. Implementing the Loan Before Change Event The before events (Before Change and Before Delete) are ideally suited for adding validation prior to making a change. You can also use them to update the fields of the record being added or changed. Before a Loan record is added or modified, there are several validations that should be performed. I will explain these, one section at a time, and then show you the resulting macro actions that you can add into your database. Making Sure the Item is Available When a Loan record is created, the user specifies the inventory item that is being checked out and the customer that is taking it. You’ll add logic to the Before Change event to ensure that this item is actually available to be checked out. If it is on hold, the logic will also ensure that this is the customer that reserved it. This code first checks to see if this is an insert; we don’t need to perform this check on an update. It then looks up the selected InventoryItem record. If the Status is not Available or On Hold, it raises an error and stops the macro. These two actions are included in a Group action, so the group can be collapsed for readability. If the Status is On Hold, it looks up the Request record that is associated with this inventory item. If the requesting customer is not the same as the one checking out the item, the macro raises an error. When an error is raised on a before event, the error message is displayed in a pop-up window and the update is aborted. To add this Data Macro, perform the following steps: CHAPTER 3 USING DATA MACROS 62 1. Open the Loan table in the Datasheet View. 2. From the Table tab, click the Before Change button. This will display a blank macro. 3. Figure 3-12 shows how this logic should be implemented. Enter these actions into the Macro Editor. Figure 3-12. Implementing the availability logic CHAPTER 3 USING DATA MACROS 63 Calculating the Due Date Recall from the table design in Chapter 2 that the loan period is defined on the Media table. To determine the due date of a new Loan record, we’ll need to look up the LoanPeriod from the Media table and add it to the current date. We will only perform this logic when this is an insert and when the DueDate field is not already specified. To accomplish this, we’ll need to perform a series of nested lookups. We’ll first find the InventoryItem record and then the associated Item record, and then we can get the Media record. The DueDate field is then updated using a SetField action. The FormatDateTime() function is used to strip off the time portion. Also, note that an EditRecord action is not needed in a before event, because only the current record can be updated. Add the actions shown in Figure 3-13 to the Before Change macro. Add these to the very end of the macro using the last Add New Action list box. Figure 3-13. Implementing the DueDate logic Calculating the Late Fee When an item is being checked back in, the CheckedIn field on the Loan record is set to the current date/time. You can tell if a particular field is being changed by using the Updated() function. If the CheckedIn field is being modified and it is not null, then we can infer that this item is being checked in. When an item is checked in, we need to see if it is overdue. You can check that by comparing the current date/time with the DueDate on the Loan record. CHAPTER 3 USING DATA MACROS 64 Note You’ll need to add a day to the due date to account for the time portion. For example, if the item is due on Jan 12 and it is currently noon on Jan 12, the due date, because it has no time portion, will be before the current date/time. By adding a day to the due date, we’re allowing them to return the item up until midnight of the 12 th . This logic computes the number of days the item is late and then looks up the daily overdue fee from the Media table. Just as with the DueDate logic, this will require several nested LookupRecord actions. Figure 3-14 shows the actions that are needed to perform this function. Add these to your current macro design. Figure 3-14. Implement the OverdueFee logic CHAPTER 3 USING DATA MACROS 65 Validating Renewals If the DueDate is being changed, you can infer that the loan has been renewed. In this case, you’ll need to see if renewals are allowed and if this will exceed the number of allowed renewals. If this renewal is not allowed, the macro should raise an error, which will abort the update. If it can be renewed, then the macro should increment the renewal count on the Loan record. To do this, you’ll need to use nested LookupRecord actions to get the Media record that determines the renewal policy. If this renewal is not allowed, it will call the RaiseError action and stop the macro. Otherwise, the Renewals count is updated. Figure 3-15 shows the necessary actions; add these to your macro design. Figure 3-15. Implementing the renewal policy CHAPTER 3 USING DATA MACROS 66 Adding the Current Loan Reference The Loan table has a reference to the InventoryItem table to indicate the specific copy that is being loaned out. It would be helpful to also have a reference in the other direction so each InventoryItem record will store the current Loan record, if it is currently checked out. You’ll add the reference now and then use data macros to set this value automatically. Note This is an example of denormalization. The current loan for an inventory item can be determined by looking up all loans for that item and returning the last one. Therefore, this is redundant information. We will add it anyway, to optimize performance, but use data macros to minimize the negative consequences. Adding the Lookup Field Open the InventoryItem table using the Design View. Add a new field named CurrentLoanID and select the Lookup Wizard Data Type. This will start the Lookup Wizard that will guide you through setting up this field. You can refer to Chapter 2 for more details about this process. 1. In the first dialog box, select the first option, which is to look up the values from another table. 2. In the second dialog box, select the Loan table. 3. In the third dialog box, select only the LoanID field. 4. In the fourth dialog box, sort by the LoanID field. 5. Accept the default values for the fifth dialog box. 6. In the sixth dialog box, select the Enable Data Integrity check box and choose the Restrict Delete option. After the CurrentLoanID field has been created, from the Design View of the InventoryItem table, select the CurrentLoanID field and the Lookup tab of the Field Properties. Make sure the Limit To List property is set to Yes. Modifying the Loan After Insert Event Now you’ll need to make a minor change to the After Insert event on the Loan table. This is the macro that you created at the beginning of this chapter. You’ve added a new field to the InventoryItem table and now you’ll update the macro to also set this field. 1. Open the Loan table in the Datasheet View. From the Table tab, click the After Insert button. This will display the existing macro logic. 2. Add another SetField action within the existing EditRecord data block. To do that, click on the EditRecord action, which will add an Add New Action dropdown list at the end of the EditRecord data block. CHAPTER 3 USING DATA MACROS 67 3. Select the SetField action. For the Name property, enter InventoryItem.CurrentLoanID, and for the Value property enter [Loan].[LoanID]. The updated macro should look like Figure 3-16. Figure 3-16. The updated After Insert macro While you’re editing this macro, there’s another section that you’ll need to add. When you check out an item that was on hold, the associated Request record should be updated and marked complete. Figure 3-17 shows the actions that you’ll need to add to the After Insert event. Add these at the end of this macro. Figure 3-17. Updating the associated Request record [...]... the EditRecord action to update the Loan record The complete macro is shown in Figure 3 -24 Enter these actions in your macro Figure 3 -24 Calculating the OverdueFee for all loans 4 72 Save the macro and enter the name CalculateAllLateFees when prompted, as shown in Figure 3 -25 CHAPTER 3 USING DATA MACROS Figure 3 -25 Saving the CalculateAllLateFees macro Creating a User-Executed Macro To call the CalculateAllLateFees... table Access 20 10 provides a Query Wizard that will guide you through the process of creating a query Later I will also show you how to create and modify a query using the Design View Creating Select Queries A select query is used to return a subset of data For example, if you wanted to see all the InventoryItem records that are currently checked out You could do this by creating a query that provides... save this macro When prompted, enter the name AssignPendingRequest as shown in Figure 3 -22 70 CHAPTER 3 USING DATA MACROS Figure 3 -22 Entering the macro name Calling a Named Macro Now you’ll need to implement the After Insert and After Update events 1 Click the After Insert button, which will create a blank macro 2 In the Add New Action dropdown list select the If action For the condition enter [InventoryItem].[Status]... are different actions available to you 2 In the Add New Action dropdown list, select the RunDataMacro action Then select the CalculateAllLateFees macro from the dropdown list The complete macro is shown in Figure 3 -26 Figure 3 -26 Calling the CalculateAlllateFees data macro 3 Click the Save icon at the top of the window and enter the name CalculateLateFees when prompted You should now have a Macro listed... Designing Queries In this chapter, you’ll design queries that will be included with your Library application Throughout this project, you’ll be creating a lot of queries This chapter will introduce the basic concepts that you’ll need to understand when creating and using queries in Access 20 10 You’ll create a few sample queries in this chapter, and then create the remainder in subsequent chapters as necessary... Figure 3 -20 69 CHAPTER 3 USING DATA MACROS Figure 3 -20 Creating a named macro This macro needs to look for a Request record for the current item (the one becoming available) and is in Pending status Because this query could return multiple records, you’ll use ForEachRecord action After the first record is processed, it will call the ExitForEachRecord action to exit the for-next loop Figure 3 -21 shows... InventoryItem record By joining the additional tables, you will not increase the number of rows Using the Join Properties Right-click the join between the Item and the InventoryItem table and click the Join Properties link This will display the Join Properties dialog box shown in Figure 4-8 Figure 4-8 The Join Properties dialog box When joining two tables, one table is referred to as the left table and the other... see from the Join Properties dialog box that Item is the left table and InventoryItem is the right table 82 CHAPTER 4 DESIGNING QUERIES ■ Note Because queries in Access are normally displayed graphically, you might think that the left table is the one on the left side of the join in the Design View In this case that happens to be true, but it is purely coincidental If you look at the properties for... Figure 3 -21 Implementing a named macro Named macros support parameters so you can pass information to them However, when a named macro is called from a data event such as After Update, the data contexts from the initiating event are carried into the named macro So this macro can access the InventoryItem data context because it was in the initiating event Click the Save button to save this macro When prompted,... [InventoryItem].[Status] = “On Hold.” For the action select RunDataMacro from the dropdown list 3 The Macro Name property is a dropdown list that shows all of the existing named macros There should only be one; select InventoryItem.AssignPendingRequest The macro should look like Figure 3 -23 Figure 3 -23 The InventoryItem After Insert event Save this macro and close the Macro Editor Then click the After Update . queries are used to insert, update, or delete records from a table. Access 20 10 provides a Query Wizard that will guide you through the process of creating a query. Later I will also show you how to. Throughout this project, you’ll be creating a lot of queries. This chapter will introduce the basic concepts that you’ll need to understand when creating and using queries in Access 20 10. You’ll. When prompted, enter the name AssignPendingRequest as shown in Figure 3 -22 . CHAPTER 3 USING DATA MACROS 71 Figure 3 -22 . Entering the macro name Calling a Named Macro Now you’ll need to