I am in the performance testing stage of my customization. It basically looks at all of the lines in the order and sums up the total order weight. It also does a volume calculation as well. I’m using the part adapter get by ID (taking the part num from the order line). Performance is okay, but I’m thinking it may be improved. On orders with large quantites or more than 10 lines it can take 1 minute to calculate.
Does the community approve, or can the code be tweaked to be more efficient? Thanks!
private void calcOrderWeightAndPalletCount()
{
int palletVolume = 90;
decimal totalOrderVolume = 0;
decimal totalOrderWeight = 0;
var currentOrderView = oTrans.Factory(“OrderDtl”); // Get the current UI view
decimal lineOrderQty;
decimal totalLineweight;
decimal totalLineVolume;
decimal partNetWeight;
decimal partNetVolume;
string currentLinePart; //Get the selected part so we can pull part weight info from the adapter
PartAdapter partAdapter = new PartAdapter(oTrans); //Create the part adapter so we have access to part database info
DataRow partAdapterRow;
partAdapter.BOConnect(); // connect to our part adapter
if (currentOrderView.dataView.Count == 0)
{
MessageBox.Show("No Order Line(s)");
}
else
{
var currentOrderRow = currentOrderView.dataView[currentOrderView.Row]; // Get the currently selected record/row from the ui view
for (int i = 0; i < currentOrderView.dataView.Count; i++)
{
currentOrderRow = currentOrderView.dataView[i];// Look at the current order row
currentLinePart = currentOrderRow["PartNum"].ToString();// Grab the part num from the current row
lineOrderQty = (decimal)currentOrderRow["SellingQuantity"];// Grab the order quantity from the current row
if (lineOrderQty != 0)
{
if (partAdapter.GetByID(currentLinePart)) //Ensure we have a part
{
partAdapterRow = partAdapter.PartData.Part.Rows[i]; //Create the part data row for us to work with
partNetWeight = (decimal)partAdapterRow["NetWeight"]; //Pull the weight information from the row
partNetVolume = (decimal)partAdapterRow["NetVolume"]; //Pull the volume information from the row
totalLineweight = lineOrderQty * partNetWeight; //Calculate the total weight of the line
totalOrderWeight += totalLineweight; //Running total for the order
totalLineVolume = lineOrderQty * partNetVolume; //Calculate the total volume of the line
totalOrderVolume += totalLineVolume; //Running total for the order
}
}
}
txtTotalOrderWeight.Text = totalOrderWeight.ToString();//Display in our UI
finalPalletCount = (int)Math.Ceiling((totalOrderVolume / palletVolume));//Run the formula for pallet calculation
txtPalletCount.Text = finalPalletCount.ToString();//Display in our UI
if (totalOrderWeight > 0)
{
txtTotalOrderWeight.BackColor = Color.LightGreen; //Highlight the change
}
if (finalPalletCount > 0)
{
txtPalletCount.BackColor = Color.LightGreen; //Highlight the change
}
}
partAdapter.Dispose(); //Cleanup
}
Looks good to me. If you wanted to shave a little bit of time you could scrap the PartAdapter and it’s GetByID and instead use a BOReader.
I think I’d grab all of the pn’s and slap em in a whereclause and return only the fields i actually needed (looks like net wt and volume)
then look at that ds for pn info
pseudo might be like this:
var pns = currentOrderView.dataView.Where(o => o.SellingQty > 0).Select(o => o.PartNum);
string whereC = "PartNum in (parts)"; //obviously you'd have to build this
var myPartDatas = BOReader.GetRows(whereC,"NetWeight, Volume"); //cant recall the actual sig here
foreach(currenOrderView)
{
// your old logic - except instead of GetByID, find your data in myPartDatas
}
How many times does this method get called? If it’s more than once, you might consider filling out a data structure with the data needed from the part adapter upon load (or some other basic event) and then performing all calculations against the custom data structure.
This method is called once on a button click event. The part adapter getbyID method is called on every line of an order during method execution to look up the part info from the line.
I’ll play around with staging the data in a ds first and getting it out of there during method execution. I’ll report back on the performance!
This is taking me back to my data structures university course
The idea is you get rid of all of the overhead of each call PLUS you return a smaller packet. Win - Win although I cant guess at how much it would (if any) save you. If you try it, please let us know how it performs!
Ouch and Double Ouch!! Just because you can, doesn’t mean you should.
GetByID is generally the heaviest weight call you can make on any BO and while the BO Reader is a better option, it is still calling the same Method on the Server (GetByID is a wrapper over GetRows) so the Server processing weight is the same. That said, with BO Reader you do save a lot on the wire traffic and associated processing.
I think I would try and do this using a BAQ and even if you are not able to Sum the data in the BAQ (you should be able to), the resulting table will be much quicker to work with and your AppServer and SQL Server will thank you…
I switched the part look up from part adapter get by ID to a dynamic query adapter using a baq that pulls the info from the part table that takes the current line partnum as a parameter.
WOW! The increase in performance of the calculation is incredible!
With the Part adapter GetByID method my calculation averaged a 22.7 Second exec time. With the Dynamic Query Adapter using a BAQ to grab the same info the calculation averaged 0.589 Second exec time.
The only downside is having to manage a BAQ with a method but with good documentation and organization that shouldn’t be a problem. Id rather do that than have my users wait 1 min on a calculation on each order throughout the day.
Thanks everyone!
Keep the combo Dynamic query adapter and accompanying BAQ as a tool in your toolbox!
Not exactly, rich would be able to explain that better than myself. But getbyid returns all the related data to the part record, which is extensive as you’ve seen, when in reality you need 2 or 3 fields.
@Aaron_Moreng - Correct: GetByID is a “convenience” Method that Wraps GetRows and just passes the Where Clause with a single ID. GetByIDs / GetBySysRowID(s) are also GetRows wrappers.
The BOReader is a special case of a GetList / GetRows wrapper in that it calls GetList or GetRows with the appropriate Where Clause but then discards all the data returned from the underlying method call except for the columns specified as return columns. The Servers (App and SQL) still do all the work but the network usage and associated processing are greatly reduced.
GetRows - whether it is returning a single row or all rows - returns the entire data structure associated with a business “entity” - Part, Customer, Quote, Order, Job, etc. The entities just listed are all Heavy Weight and are made up of numerous related tables (parent, child, grandchild,…) and can also include independent but associated tables.
If you need the entire business entity, GetByID is fine but if you only need a few pieces of data, use a BAQ. In cases where the data that you want is logically modified by a Post Processing BPM and you are unable to emulate that logic in a BAQ, use the BOReader.