This are the business rules I want to implement. Every order item has to update the total order amount of the order. The Line Item Id of the order items has to an autonumber 1, 2, etc and not a sequence. On the order table the order date has to be current date and the order Id must be the next value of the orders_seq sequence.
Here some pics of the order and items page
This is how I did it on the orders view. First I made two calculated attributes CalculatedOrderTotal and CalculatedOrderLines on the orders entity. These attributes I use on the orders items entity. Then I generate the impl java class of the orders entity so I can change the getters of these calculated attributes.
/**Gets the attribute value for CalculatedOrderTotal, using the alias name CalculatedOrderTotal.
*/
public Double getCalculatedOrderTotal() {
RowIterator rowItr = this.getOrderItems();
Double total = 0.0;
while(rowItr.hasNext()){
Row row = rowItr.next();
Number unitPrice = (Number)row.getAttribute("UnitPrice");
Number quantity = (Number)row.getAttribute("Quantity");
total += (unitPrice.doubleValue() * quantity.intValue());
}
return total;
}
/**Setsvalue
as the attribute value for CalculatedOrderTotal.
*/
public void setCalculatedOrderTotal(Double value) {
setAttributeInternal(CALCULATEDORDERTOTAL, value);
}
/**Gets the attribute value for CalculatedOrderLines, using the alias name CalculatedOrderLines.
*/
public Number getCalculatedOrderLines() {
RowIterator rowItr = this.getOrderItems();
Number lineId = new Number(0);
while(rowItr.hasNext()){
Row row = rowItr.next();
Number lineIdRow = (Number)row.getAttribute("LineItemId");
// check the current Id is greater than lineId
if ( lineIdRow != null && lineIdRow.compareTo(lineId) == 1 ) {
lineId = lineIdRow;
}
}
return lineId;
}
/**Setsvalue
as the attribute value for CalculatedOrderLines.
*/
public void setCalculatedOrderLines(Number value) {
setAttributeInternal(CALCULATEDORDERLINES, value);
}
Now we add some code to the impl of the order items. First I try to set the next number for the line item , Then I set the unit item price of the selected product ( I can do this by using the association between order items and product information )the last step is to update the total order amount of the order
protected void prepareForDML(int dml, TransactionEvent evt) {
if (dml == DML_INSERT || dml == DML_UPDATE || dml == DML_DELETE) {
super.prepareForDML(dml,evt);
businessRules( dml);
}
}
public void businessRules(int dml){
if ( dml == DML_INSERT) {
Number row = this.getOrders().getCalculatedOrderLines();
this.setLineItemId(row.add(1));
}
if ( dml == DML_INSERT || dml == DML_UPDATE) {
ProductInformationImpl product = (ProductInformationImpl) this.getProductInformation();
if(product != null){
Number listPrice = product.getListPrice();
this.setUnitPrice(listPrice);
}
}
if ( dml == DML_UPDATE) {
Number oldQuantity = (Number)getPostedAttribute(getAttributeIndexOf("Quantity"));
System.out.println("new quantity "+this.getQuantity().toString()+" old "+oldQuantity.toString());
}
try {
this.getOrders().setOrderTotal(new Number(this.getOrders().getCalculatedOrderTotal()));;
}
catch ( Exception e) {
e.printStackTrace();
}
}
If you want to check the old and new values of an attribute then you can use getPostedAttribute to get the old value of the attribute. This is the same as :old and :new in the plsql triggers.
Now we implement the business rules on the orders entity. We add the following code to the orders impl
protected void prepareForDML(int dml, TransactionEvent evt) {
if (dml == DML_INSERT || dml == DML_UPDATE || dml == DML_DELETE) {
super.prepareForDML(dml,evt);
businessRules(dml);
}
}
public void businessRules(int dml){
if ( dml == DML_INSERT) {
SequenceImpl sequence = new SequenceImpl("ORDERS_SEQ", getDBTransaction());
this.setOrderId(sequence.getSequenceNumber());
this.setOrderDate(new Date(Date.getCurrentDate()));
}
}
In this method I set a database sequence on the Order Id and the current Date in the Order Date attribute.
Here you have the sample project it works on jdeveloper 11g and on the oe sample schema
Just want to say that it not old fashion software to let some business rules in the database model. It make sense to let some logic in the database layer instead thinking that all has to move in the middle tier. The advantages are that all rules are always applied independtly the tool that manipulate the data and that the logic applied is near the data (checks are often data intenvive consumer).
ReplyDeleteHi,
ReplyDeleteMy name is Shadi and I'm from Iran. I workd with jdeveloper 11g with jheadstart.
I read your blog and wonder if you can answer my question.
my problem is:
I have made an edit button in a form in jdeveloper 11g and I made it the way that when I push the button all the things that I want to be updated, turns to be active to update. for example you can change dropdown's value and ...
but when I push the save button, it says that there's nothing to save.
I think it gets refreshed and accept no changes.
how do you think I can make my edit button work?
Thankx in advance
Shadi Khani
Hi,
ReplyDeleteWhen you think it refreshes itself when you do a submit (save button) then you should take a look at the refresh options of the iterators in executables section of the pagedef of the jsf page.
thanks Edwin
Hi Edwin,
ReplyDeleteThanks for your help, but I did not undrestand.Could you plz tell me in more details? Where is refresh options of the iterators in executables section of the pagedef of the jsf page ?
And another question is that I could use table range in jdeveloper 10gon my tables , but in 11g I cannot see it on the tables can you tell me what should I do if I want to see table range on my tables?
Thanks Shadi
Ok,
ReplyDeletewhen you go the adf page and press the bindings tab. The you will see in the middle the executables. just press one and in the property window you can change the rangesize and the refresh property
the tables fetches automatically the next rows when you press the scrollbar
thanks edwin
Hi I solved it,
ReplyDeleteset immediate on false on the edit button. please take a look at the jsf page lifecycle to see what immediate does
put your backing bean in adfc-config.xml , no need for faces-config.xml
and don't use request use session because when you press the save button and make a round tip to the server , the bean will be initialized again and the boolean value will be false.
so put this to this session en voila.
Good luck and thanks Edwin
Thank you Edwin,
ReplyDeleteYou're a brilliant thinker.
Thanks Shadi
Edwin can you tell me why the page stays in edition mode after the edition is done when I press the save button? Can you fix it ? I have already sent you another demo to see what happens when you go through other pages after edittion. Could you check my email plz ?
ReplyDeleteThanks Shadi.
Hi Shadi,
ReplyDeleteThat is because the managed bean is in session mode. So after a succesfull commit set the edit variable to false.
What you should do is make your own setActionListener method in the bean and use this on the commit button. Then get a handle to the commit operation in the pagedef , See if there are errors on this operationbinding and after that set the edit variable on false ) .
see this blog for the code
http://biemond.blogspot.com/2009/03/some-handy-code-for-backing-beans-adf.html
or something like this
// get the binding container
BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
// get an Action or MethodAction
OperationBinding method = bindings.getOperationBinding("commit");
method.execute();
List errors = method.getErrors();
// show error
// reset edit variable
hope this helps
Edwin
Hi Edwin,
ReplyDeleteI did it myself.
Plz don't check the "MyDemo" project
Thanx for your help.
Thank you Shadi
Hi,
ReplyDeletegreat job, you learned something.
thanks Edwin