Working With Fetch Specifications

After you create and configure entities in EOModeler, you can also use it to build queries on those entities called fetch specifications. A fetch specification (a com.webobjects.eocontrol.EOFetchSpecification object) is the object Enterprise Objects uses to get data from a data source.

Each fetch specification can contain a qualifier, which fetches only those rows that meet the criteria in the qualifier. A fetch specification allows you to specify a sort ordering to sort the rows of data returned. A fetch specification can also have other characteristics, as discussed in this chapter.

This chapter is organized in the following sections:

Creating a Fetch Specification

Although you can create fetch specifications programmatically, it’s easier and less error-prone to create and configure them in EOModeler. To create a fetch specification in EOModeler:

  1. Select the entity with which the fetch specification is associated.

    A fetch specification is related to a single entity, so all the fields used in a particular fetch specification are relative to the entity to which it belongs.

  2. Choose Add Fetch Specification from the Property menu.

  3. Type a name for the fetch specification in the Fetch Specification Name field and press Return.

    Figure 7-1  A sample fetch specification
    A sample fetch specification

Figure 7-1 shows a fetch specification called SearchListing in an entity called Listing. There are six panes in the fetch specification builder, which you can use to configure a fetch specification. They are each described in the following sections.

Building a Qualifier

A qualifier (a concrete instance of a com.webobjects.eocontrol.EOQualifier subclass) restricts the rows of data that are fetched with a fetch specification object. For example, in a real estate application, you may want to retrieve the records of homes that are priced under $500,000. To build the qualifier for this query in EOModeler:

  1. Using the Real Estate model in the WebObjects examples folder, add a fetch specification to the Listing entity.

  2. In the Qualifier pane, click in the text field below the list of attributes, then select the askingPrice attribute, and type < 500000 after it, as shown in Figure 7-2.

    Figure 7-2  Static qualifier
    Static qualifier

This fetch specification returns only those listings whose asking price is under $500,000. Although you may have the need to build a static qualifier like this one, you’ll most often want to use qualifier variables to supply dynamic values to qualifiers, such as $350,000 or $700,000 in this example. This is described in Using Qualifier Variables.

Creating Compound Qualifiers

You can also use the qualifier builder to create compound qualifiers made up of multiple expressions. For example, you may want to build a qualifier that restricts a query on home listings to homes whose asking price is less than $500,000 but greater than $350,000.

To create a compound qualifier from the qualifier created in Building a Qualifier, select the expression askingPrice < 500000 and click the And button. Then add a second expression by again selecting the askingPrice attribute from the attribute list and completing the expression with > 350000, as shown in Figure 7-3.

Figure 7-3  A compound qualifier
A compound qualifier

As you build up a complex query, the text field at the bottom of the Qualifier pane updates to include the full text of the compound qualifier. Instead of building up expressions one by one with the And, Or, and Not buttons, you can type directly into this text field. The qualifier builder parses this string and displays the individual expressions.

Using Qualifier Variables

You can specify static criteria for a fetch specification’s qualifier, as is done in Building a Qualifier and in Creating Compound Qualifiers. However, such a qualifier is of limited use. More commonly, you want to specify the form of a qualifier and let users supply specific values when they run the application. You can do this with qualifier variables.

You specify a qualifier variable using the dollar sign character ($), as in the following:

askingPrice < $maxPrice

You can build this qualifier in EOModeler as specified in the previous sections and then bind its qualifier variables to your application’s user interface. You do this by dragging a fetch specification into either WebObjects Builder or Interface Builder and then binding user interface elements to keys in the display group that correspond to the fetch specification’s variables.

Figure 7-4 shows the queryBindings attribute of a display group that was added to a WOComponent. The queryBindings attribute includes bindings for the attributes that are the keys of qualifiers in the fetch specification to which the display group is associated. You bind values in the user interface to these keys by making a connection between the keys and certain dynamic elements.

Figure 7-4  Fetch specification bindings in WebObjects Builder
Fetch specification bindings in WebObjects Builder

You can also bind qualifier variables to values in your application programmatically, as described in Using Named Fetch Specifications.

Assigning a Sort Ordering

It’s common to want a fetch specification to return a sorted array of objects. You can assign a sort ordering to a fetch specification in the Sort Ordering pane of the fetch specification builder.

Simply choose an attribute on which to sort and click Add. The order in which you add attributes specifies the weight to assign to them. Figure 7-5 shows a sort ordering that sorts first on whether the listing is sold and second on the number of bedrooms.

Figure 7-5  Sort ordering
Sort ordering

You can also specify an ascending or descending order to sort on for each attribute and whether to perform case-sensitive or case-insensitive comparison. Figure 7-5 specifies an ascending order for the isSold attribute and a descending order for the bedrooms attribute.

Prefetching

Among the numerous options you can use to tune a fetch specification’s behavior is prefetching. In the Prefetching pane of the fetch specification builder, you identify relationships that should be fetched along with the objects specified by the fetch specification. For example, when fetching Listing objects, you can prefetch associated listingFeatures and suggestedCustomers relationships. This tells Enterprise Objects to retrieve a Listing’s listedFeatures and suggestedCustomers relationships along with the Listing itself, as opposed to creating faults for the objects in those relationships.

Although prefetching increases the initial fetch cost, it can improve overall performance by reducing the number of round trips made to the data source.

To specify a relationship to prefetch, in the Prefetching pane of the fetch specification builder, select the relationship you want to prefetch and click Add, as shown in Figure 7-6.

Figure 7-6  Configure prefetching
Configure prefetching

Configuring Raw Row Fetching

When you perform a fetch in an Enterprise Objects application, the information from the database is fetched and stored in a graph of enterprise objects. This object graph provides many advantages, but it can be large and complex.

If you’re creating a simple application, you may not need all the benefits of enterprise objects and the object graph. For example, an application that simply displays information from a database without ever performing database updates and without ever traversing relationships might be just as well served by fetching the information into a set of dictionaries rather than a set of enterprise objects.

You can do this in Enterprise Objects by using raw row fetching. In raw row fetching, each row from the database is fetched into an NSDictionary object.

When you use raw row fetching, you lose some important features:

And, if you need an enterprise object at some point in your application, you can easily construct one from a raw row dictionary.

You can configure raw row fetching in the Raw Fetch pane of the fetch specification builder. In this pane, you can choose to fetch all or some of the attributes of a particular entity as raw rows.

Other Fetch Specification Options

The Options pane of the fetch specification builder lets you configure other aspects of a fetch specification. These other aspects are usually used for performance tuning. These are the options:

Using Named Fetch Specifications

Fetch specifications you build in EOModeler are referred to as named fetch specifications. To use a named fetch specification requires that you get hold of the model object in which the fetch specification exists. The code in Listing 7-1 retrieves a fetch specification called “MyFetch” in an entity named “Listing” by looking for it in all the models in the application’s default model group.

Listing 7-1  Get a fetch specification programmatically

EOModelGroup modelGroup = EOModelGroup.defaultGroup();
EOFetchSpecification fs = modelGroup.fetchSpecificationNamed(“MyFetch”, “Listing”);

If the fetch specification has qualifier variables, you can bind them to a dictionary of values in the application using the code in Listing 7-2.

Listing 7-2  Bind qualifier variables

fs = fs.fetchSpecificationWithQualifierBindings(dictionary);

In Listing 7-2, the variable bindings is an NSDictionary object of key-value pairs. So if you have three qualifier variables in the fetch specification called $askingPrice, $bedrooms, and $bathrooms, the dictionary object would look like Table 7-1.

Table 7-1  Bindings dictionary

Key

Value

askingPrice

500000

bedrooms

4

bathrooms

3

If you define a qualifier like this:

(askingPrice < $askingPrice) and (bedrooms = $bedrooms) and (bathrooms = $bathrooms)

then the qualifier variables are replaced by 500000 (askingPrice), 4 (bedrooms), and 3 (bathrooms).

You can construct the dictionary in Table 7-1 with this code:

NSMutableDictionary dictionary = new NSMutableDictionary();
dictionary.takeValueForKey(“500000”, “askingPrice”);
dictionary.takeValueForKey(“4”, “bedrooms”);
dictionary.takeValueForKey(“3”, “bathrooms”);

The complete code listing for this example appears is:

EOModelGroup modelGroup = EOModelGroup.defaultGroup();
EOFetchSpecification fs = modelGroup.fetchSpecificationNamed(“MyFetch”, “Listing”);
fs = fs.fetchSpecificationWithQualifierBindings(dictionary);
NSMutableDictionary dictionary = new NSMutableDictionary();
dictionary.takeValueForKey(“500000”, “askingPrice”);
dictionary.takeValueForKey(“4”, “bedrooms”);
dictionary.takeValueForKey(“3”, “bathrooms”);