org.jaffa.beans.moulding.data.criteria package
This contains all the base classes used for Criteria Data Access Objects.
How to control what is returned in a domain object graph
The CriteriaDAO object supports a setResultGraphRules(java.lang.String[] resultGraphRules)
method to control the scope of the domain graph retrieved. This is important for performance reasons, as
many Domain Objects have a large number of related objects, and Domain Object Graph
based queries can bring back large sets of related domain objects. Sometimes this is required, but many
times we only want a subset of that data. By specifying just a subset of data, the number of internal queries
that are performed to build the Graph, and the volume of unneeded data being returned can be dramatically
reduced, and hence yield a faster response.
The section below explains how with a given domain object graph, these domain object graph filtering rules
can be applied.
We will use the following example
The root of this graph is a 'vendor'.
The 'vendor' has the following fields
- vendorCode (Key)
- vendorName (Mandatory)
- cageCode
The 'vendor' has a foreign Object
The 'vendor' has related objects
- comments (one-to-one)
- sites (one-to-many)
The foreign object 'businessType' has two fields
The 'site' object has the following fields
- siteCode (Key)
- addressLine
- city
- country
- state
- zip
- taxRate
- methodOfPayment
- rating
The 'site' has a related object
The 'contact' object has the following fields
- sequence (Key)
- contactName
- addressLine
- city
- country
- state
- zip
If we now 'list' the total set of fields in this domain object graph,
we get the following set of field references. (Note the dot(.) notation
is similar to that now used in the JSP 2.0 expression language)
businessType.businessType
businessType.description
cageCode
comments
comments.text
vendorCode
vendorName
vendorSites
vendorSites.addressLine
vendorSites.city
vendorSites.contacts
vendorSites.contacts.addressLine
vendorSites.contacts.city
vendorSites.contacts.contactName
vendorSites.contacts.country
vendorSites.contacts.sequence
vendorSites.contacts.state
vendorSites.contacts.zip
vendorSites.country
vendorSites.methodOfPayment
vendorSites.rating
vendorSites.siteCode
vendorSites.state
vendorSites.taxRate
vendorSites.zip
1. Basic filters
Filters support *, which matches a single field name, or ** which matches multiple property names
We assume all field names match the regular expression [a-zA-Z_0-9]
1.1 The default
The default filter is *, which matches all fields in the primary object.
setRules = null
or
setRules = "*"
The above rules will give the following resulting map
vendorName
vendorCode
businessType
businessType.businessType
cageCode
Note: that we filter out the vendorSites object as this is an array of object, and no fields have
requested from this object. The infers the default behavior is that NO one-to-one/one-to-many objects
will be automatically included, unless specifically requested.
Note: we have included businessType this is a foreign object, and in this case we need an instance
of the businessType object to hold the business type value. However, no other fields in the businessType
object will be filled in, unless specifically requested.
1.2 Include the world
We want to include not just the main fields, but all fields on related and foreign objects
setRules = "**" (where "**" mean match 'anything')
or
setRules = "**.*","*" (where "**.*" means any match all fields on 'anything'
and "*" also include the fields on the root object too)
The above rules will give the following resulting map
businessType
businessType.businessType
businessType.description
cageCode
comments
comments.text
vendorCode
vendorName
vendorSites
vendorSites.addressLine
vendorSites.city
vendorSites.contacts
vendorSites.contacts.addressLine
vendorSites.contacts.city
vendorSites.contacts.contactName
vendorSites.contacts.country
vendorSites.contacts.sequence
vendorSites.contacts.state
vendorSites.contacts.zip
vendorSites.country
vendorSites.methodOfPayment
vendorSites.rating
vendorSites.siteCode
vendorSites.state
vendorSites.taxRate
vendorSites.zip
1.3 Includes and Excludes
If a rule beings with a '-' (minus) sign it means exclude all fields that match
this rule, if a rule beings with '+' (plus) it means include all fields that match
this rule. If neither '+' or '-' is used then '+' is assumed, and the rule is inclusive.
In this case the default rule set is really '+*'
The rules are processed in the order the are supplied, and once a rule is processed that either
included or excludes a field, no more rules are read. If no rule is found that included or excludes
a given field, that field will be excluded. To change the default behavior to include any field that
is not referenced put a 'catch-all' rule as the last rule (i.e. use either '**' or something similar)
This is an example of how the order works
setRules = "*","+vendorSites.*","-vendorSites.taxRate","-vendorSites.rating"
Will return
vendorName
vendorCode
vendorSites.siteCode
vendorSites.country
vendorSites.taxRate
vendorSites.addressLine
vendorSites.state
vendorSites.methodOfPayment
vendorSites.zip
vendorSites.rating
vendorSites.city
businessType
cageCode
Not the two fields taxRate and rating are still there, since the "+vendorSites.*" rule was first
and explicitly included them. The correct way to do this would have been...
setRules = "-vendorSites.taxRate","-vendorSites.rating","+vendorSites.*","*"
Which would have given
vendorName
vendorCode
vendorSites.siteCode
vendorSites.country
vendorSites.addressLine
vendorSites.state
vendorSites.methodOfPayment
vendorSites.zip
vendorSites.city
businessType
cageCode
1.4. Basic includes
We saw that
setRules = "*"
Gives the following
vendorName
vendorCode
businessType
cageCode
The businessType only has the key field in, but we want the description too
We should use the following
setRules = "*","businessType.description"
or
setRules = "*","businessType.*"
Gives the following
vendorName
vendorCode
businessType
businessType.businessType
businessType.description
cageCode
We now want just the list of sites as well
setRules = "*","businessType.*","vendorSites.siteCode"
Gives the following
vendorName
vendorCode
vendorSites
vendorSites.siteCode
businessType
businessType.businessType
businessType.description
cageCode
And now per site, we want the contact name and address
setRules = "*","businessType.*","vendorSites.siteCode","vendorSites.contacts.*"
Gives the following
vendorName
vendorCode
vendorSites
vendorSites.contacts
vendorSites.contacts.contactName
vendorSites.contacts.country
vendorSites.contacts.addressLine
vendorSites.contacts.state
vendorSites.contacts.zip
vendorSites.contacts.sequence
vendorSites.contacts.city
vendorSites.siteCode
businessType
businessType.businessType
businessType.description
cageCode
Now i want just the site and contact addresses
setRules = "vendorCode","vendorName","vendorSites.siteCode","vendorSites.contacts.contactName",
"**.addressLine","**.city","**.state","**.zip","**.country"
Gives the following
vendorName
vendorCode
vendorSites
vendorSites.contacts
vendorSites.contacts.contactName
vendorSites.contacts.country
vendorSites.contacts.addressLine
vendorSites.contacts.state
vendorSites.contacts.zip
vendorSites.contacts.city
vendorSites.siteCode
vendorSites.country
vendorSites.addressLine
vendorSites.state
vendorSites.zip
vendorSites.city
2. Rules for related objects
Whether the relationship is one-to-many (Array of Objects), or just one-to-one (Object)
the related object is no included in the results unless at least one field in the
related object is referenced. In the above example referenced to "vendorSites" or
"vendorSites.contacts" are meaningless, and will not include those objects. To be
included they should be suffixed with a ".*".
So the following scenarios occur
setRules = "vendorSites"
Will return
<nothing>
setRules = "vendorSites.*"
Will return
vendorSites
vendorSites.siteCode
vendorSites.country
vendorSites.taxRate
vendorSites.addressLine
vendorSites.state
vendorSites.methodOfPayment
vendorSites.zip
vendorSites.rating
vendorSites.city
setRules = "vendorSites.**"
Will return
vendorSites
vendorSites.contacts
vendorSites.contacts.contactName
vendorSites.contacts.country
vendorSites.contacts.addressLine
vendorSites.contacts.state
vendorSites.contacts.zip
vendorSites.contacts.sequence
vendorSites.contacts.city
vendorSites.siteCode
vendorSites.country
vendorSites.taxRate
vendorSites.addressLine
vendorSites.state
vendorSites.methodOfPayment
vendorSites.zip
vendorSites.rating
vendorSites.city
3. Rules for foreign objects
When a foreign object is referenced by a main object there are 3 scenarios to look at
- is there a need for the object. This is the case when the foreign keys are null. In
this case the foreign object reference is null
- is there a need to retrieve a foreign object? if we can avoid loading foreign objects then
this will improve performance.
- we need to load the foreign object, as the user wants to access fields from that foreign object.
In both scenarios (b) and (c) a foreign object will be return. In the case of (b) only the fields
that make up the object key will be populated, as these can be derived from the foreign keys in the
main object. In scenario (c) we need to load the foreign object so we can access other data from it
How do we detect when to load and not load the object?
We first need to see if either the object property, or and of its fields are referenced.
In the above case we will look at the 'businessType' on the vendor. Any of the following
referenced will cause the object to be returned...
businessType
businessType.businessType
businessType.description
but only a reference to description required the record to be read from the database.
The filtering engine will internally do the following
- apply the filter rules to any field reference, and included it if valid.
if it is valid the following additional rules will be applied
- if the foreign object field is referenced, it will leave it in the 'fields to include' list
- if one of the primary keys of the object is referenced it will
- add in a reference to the object, like in (b), if there is not one already
- it will remove the primary key reference, as the primary fields will ALWAYS be returned
regardless of any rules that may try and exclude them
- any field reference on the foreign object that is not a primary key field will be left in the list
So the following scenarios occur
setRules = "*"
Will return
...
businessType
businessType.businessType
setRules = "businessType"
Will return
businessType
businessType.businessType
setRules = "businessType.businessType"
Will return
businessType
businessType.businessType
setRules = "businessType.description"
Will return
businessType
businessType.businessType
businessType.description
setRules = "businessType.*"
Will return
businessType
businessType.businessType
businessType.description
setRules = "-businessType.businessType","businessType"
Will return
businessType
businessType.businessType
setRules = "-businessType.description","businessType.*"
Will return
businessType
businessType.businessType
setRules = "-businessType.businessType","businessType.*"
Will return
businessType
businessType.businessType
businessType.description
|