Jul 22, 2007

Δημιουργώντας σελίδες αναζήτησης σε ADF που θα χρησιμοποιούν λογικές διαζεύξεις (OR)

Η κατασκευή μιας σελίδας αναζήτησης στο ADF, είναι υπόθεση 2 λεπτών: διαλέγουμε το business object μας, το μεταφέρουμε με drag and drop στην σελίδα μας, το διαμορφώνουμε ως ADF Search Form και τέλος ορίζουμε ένα δεύτερο iterator για τα αποτελέσματα, όπως άλλωστε περιγράφεται στο ADF Developer's Guide (http://download.oracle.com/docs/pdf/B25947_01.pdf). Η λειτουργικότητα που παρέχεται με αυτόν τον τρόπο μας επιτρέπει να εισάγουμε πολλαπλά κριτήρια αναζήτησης, που όλα μεταξύ τους σχηματίζουν μια αλυσίδα από ANDs στο επίπεδο του where clause που θα κατατεθεί στη βάση. Είναι δυνατόν όμως να θέλουμε μια διαφορετική συμπεριφορά σε αυτήν την πρότυπα κατασκευασμένη σελίδα, ώστε η συμπλήρωση ενός ή περισσότερων κριτηρίων να εκλαμβάνεται ως λογική διάζευξη (OR) μεταξύ τους. H επέμβαση αυτή χρειάζεται λίγο προγραμματισμό σε Java και γι' αυτό το λόγο είναι χρήσιμο να δοθούν μερικές παραπάνω πληροφορίες.

Προκειμένου να εφαρμοστούν δυναμικά κριτήρια αναζήτησης, τα ADF BC View Objects διαθέτουν δυο τρόπους. Ο πρώτος αφορά την δυναμική επισύναψη του where clause με την μέθοδο ViewObject.setWhereClause(String whereclause), όπως για παράδειγμα orders.setWhereClause("order_id = 100 AND quantity > 20"); οπότε προσθέτουμε προγραμματιστικά το SQL statement. Ο δεύτερος τρόπος είναι πιο συγκροτημένος και προκαλεί την ομαδοποίηση των κριτηρίων αναζήτησης, με την χρήση της γλώσσας Query-By-Example (QBE) που μπορεί να περιλαμβάνει μεταχαρακτήρες ('%', '>') ή λέξεις της SQL ('LIKE', 'BETWEEN',...) θέτοντας την κλάση ViewCriteria στο ViewObject μας με την μέθοδο ViewObject.applyViewCriteria(ViewCriteria criteria) Με τη σειρά της, η κλάση ViewCriteria, περιέχει τις γραμμές των κριτηρίων (κλάση ViewCriteriaRow). Για την εναργέστερη κατανόηση των παραπάνω, παραθέτω ένα τροποποιημένο παράδειγμα από το JavaDoc του ADF BC, που αναζητεί με βάση είτε τον τίτλο του Manager, είτε τον κωδικό του τμήματος.
// Create and populate criteria rows to support query-by-example.
// Supposing that this method is written within an Application Module class.
ViewObject empView = getEmployeeView();
// Define a criteria container.
ViewCriteria vc = empView.createViewCriteria();
// Define a criteria row.
ViewCriteriaRow vcRow = vc.createViewCriteriaRow();

// Define criterion 1.
vcRow.setAttribute("Job", "MANAGER");
// Append criterion to the container.
vc.addElement(vcRow);

// Define criterion 2.
vcRow.setAttribute("Deptno", "= 10");
// Define conjunction statement (AND/OR/NOT)
vcRow.setConjunction(vcRow.VCROW_CONJ_OR);
// Append criterion to the container.
vc.addElement(vcRow);
// Apply criteria.
empView.applyViewCriteria(vc);
// Final query: job = 'MANAGER' OR dept_no = 10
// Execute query. View object is now populated with search results.
empView.executeQuery();

Αξίζει να σημειωθεί πως είναι δυνατόν οι γραμμές των κριτηρίων (αντικείμενα τύπου ViewCriteriaRow) να περιλαμβάνουν πολλαπλά κριτήρια (που ορίζονται με την μέθοδο setAttribute()) και αντίστοιχα να εφαρμοστούν πολλαπλές γραμμές κριτηρίων σε ένα ViewObject. Επίσης, η μέθοδος setConjunction() καθορίζει πως θα συνδέεται η τρέχουσα γραμμή με την προηγούμενη γραμμή κριτηρίων (με AND, OR ή ΝΟΤ), έχοντας ως προκαθορισμένη (default) συμπεριφορά την διάζευξη (OR) Με την αυτοματοποιημένη κατασκευή φορμών αναζήτησης στις σελίδες JSF, ορίζεται μια γραμμή κριτηρίων που συνδέει με το λογικό AND τα κριτήρια που κατάθεσε ο χρήστης.

Δημιουργούμε λοιπόν μια νέα φόρμα αναζήτησης κάνοντας drag and drop ένα View object μας, οπότε κατασκευάζεται η Search σελίδα.


Ακολουθώντας τις οδηγίες τους ADF Developer's Guide, και ειδικά του κεφαλαίου "Creating a Search Form", καταλήγουμε σε μια σελίδα που θα εμφανίζει στο πάνω μέρος τα κριτήρια αναζήτησης, ένα κουμπί που θα κάνει την εκτέλεση του query και στο κάτω μέρος τα αποτελέσματα, χρησιμοποιώντας ένα δεύτερο iterator. Επίσης, κάνουμε drag-and-drop, ένα δεύτερο Command Button, δίπλα στο Execute, που θα υλοποιήσει την διαζευκτική λογική μας. Κάτι ανάλογο δηλαδή με την ακόλουθη εικόνα.

Σε αυτό το σημείο, θα χρειαστεί να δημιουργήσουμε ένα καινούργιο Managed Bean, δηλαδή μια απλή Java κλάση (POJO) που θα υλοποιήσει τη λογική του OR κουμπιού μας. Οπότε από τη γραφική διεπαφή του faces-config.xml ορίζουμε ένα νέο Managed Bean.

Επιστρέφουμε στη σελίδα μας και κάνουμε διπλό click πάνω στο κουμπί "Execute". Θα εμφανιστεί μια καρτέλα που θα μας ζητήσει το όνομα του Managed Bean και της μεθόδου που θα εκτελεστεί μόλις γίνει click στο κουμπί. Συμπληρώνουμε κατά βούληση, χρησιμοποιώντας το Managed Bean του προηγούμενου βήματος. Κάτι τέτοιο το χρειαζόμαστε, προκειμένου να προστεθεί ως Managed property o BindingContainer στο Managed Bean που μόλις κατασκευάσαμε, γι' αυτό σε κάθε περίπτωση κρατάμε ενεργή την ένδειξη "Generate ADF Binding Code".

Τώρα, θα κάνουμε διπλό click και στο κουμπί που θα υλοποιήσει τη λογική του OR (το δεύτερο κουμπί στη σελίδα μας), και θα δημιουργήσουμε μια νέα μέθοδο που θα αναλάβει την εξυπηρέτηση του γεγονότος (έστω searchByOr_action()) To κλειδί για την υλοποίηση της OR λογικής είναι να έχουμε πρόσβαση στα ήδη κατατεθειμένα από τον χρήστη κριτήρια. Τούτο επιτυγχάνεται όταν θα αποκτήσουμε πρόσβαση στον Iterator που βρίσκεται σε Find mode, δηλαδή η function μας θα δείχνει κάπως ως εξής:
public String searchByOr_action() {
BindingContainer bindings = getBindings();
// Cast binding iterator into DataControl binding iterator.
DCBindingContainer bc = (DCBindingContainer) getBindings();
// Retrieve iterator declared in Find mode.
DCIteratorBinding iter = bc.findIteratorBinding("OrderItemsView1Iterator");
// Retrieve already submitted criteria.
ViewCriteria criteria = iter.getViewCriteria();
// ....
// Redirect control to the same page.
return null;
}

Από τη στιγμή που έχουμε στη διάθεσή μας τα κριτήρια που κατατέθηκαν (με την μέθοδο iter.getViewCriteria()) τότε απλά απομένει το να δημιουργήσουμε νέες γραμμές κριτηρίων που θα ενώνονται μαζί τους με τη διάζευξη (OR) που είναι εξάλλου και η προκαθορισμένη συμπεριφορά και να εφαρμόσουμε αυτά τα κριτήρια:
ViewCriteriaRow line = (ViewCriteriaRow)criteria.first();

// Initialize new criteria.
ViewCriteria newCriteria = iter.getViewObject().createViewCriteria();
// Iterate over submitted criteria.
for (int i=0, nCriteria = line.getAttributeCount(); i <>
// Create new criteria line.
ViewCriteriaRow row = newCriteria.createViewCriteriaRow();
row.setAttribute(i, line.getAttribute(i));
newCriteria.addElement(row);
}

// Applying view criteria.
iter.getViewObject().applyViewCriteria(newCriteria);
Υλοποιώντας λοιπόν τη λογική του κουμπιού OR, η σελίδα θα εκτελεστεί ως ακολούθως:

Ανάλογα με τις υπηρεσίες που θέλουμε να προσφέρουμε στους χρήστες, το κουμπί Execute μπορεί να αφαιρεθεί εντελώς και να είναι δυνατή μόνο η αναζήτηση με βάση τη διάζευξη, διαφορετικά για να λειτουργήσουν και οι δυο μαζί θα χρειαστεί μια μικρή διόρθωση, που παρατίθεται στο code listing του Managed Bean.

Τέλος, για ακόμα πιο δυναμικά και σύνθετα κριτήρια αναζήτησης σε μια σελίδα, μια χρήσιμη παραπομπή είναι η ακόλουθη: http://my.opera.com/dominionspy/blog/2007/02/26/an-advanced-custom-search-form-for-adf

No comments: