Dictionary and condition - asp.net

I have been working on an assignment in which I have to upload some records from a file to Dictionary and manipulate.
Actually file have number of record with same invoice number and different tax values and I have to add all those values and make it only one invoice
what I'm trying to do
I'm passing values from a foreach loop to a function which check if the dictionary is empty so it will simply add first record and on second call it will check weather any record in dictionary have same invoice number so it will sum and update current tax value to one already added,
what I'm getting
when I pass 2nd value (and so on) the previous value of last entry in dictionary some how update itself with current value before even comparing which I don't want.
public jd_records jd = new jd_records();
Dictionary<int, jd_records> jdValues = new Dictionary<int, jd_records>();
//Calling values with loop while jd is a publicly declared object of class jd_records
foreach (DataRow dr in jddt.Rows)
{
//jd_records jdPass = new jd_records();
jd.supplierName = dr["Supplier"].ToString();
jd.supplierNTN = dr["Supplier NTN"].ToString();
jd.invoiceNo = dr["JDE Invoice Number"].ToString();
jd.invoiceDate = DateTime.Parse(dr["JDE Invoice Date"].ToString());
if (dr["Taxable Amount"].ToString().Equals(""))
{ jd.taxable = 0; }
else
{ jd.taxable = float.Parse(dr["Taxable Amount"].ToString()); }
if (dr["Tax To Pay"].ToString().Equals(""))
{ jd.tax = 0; }
else
{ jd.tax = float.Parse(dr["Tax To Pay"].ToString()); }
jdRecordCheck();
}
called function
public void jdRecordCheck()
{
if (jdValues.Count < 1)
{
jdValues.Add(0, jd);
}
else //previous record values (at key 0) changes to new jd value when come to this else part on execution
{
foreach (KeyValuePair<int,jd_records> jdVal in jdValues)
{
if ((jdVal.Value.supplierNTN.Equals(jd.supplierNTN)) && (jdVal.Value.invoiceNo.Equals(jd.invoiceNo)))
{
jdVal.Value.tax = jdVal.Value.tax + jd.tax;
jdVal.Value.taxable = jdVal.Value.taxable + jd.taxable;
jdValues[jdVal.Key] = jdVal.Value;
}
else
{
jdValues.Add(jdVal.Key + 1, jd);
}
}
}
}
I'll be very thankful if anyone helps.

Seems to me this would be much easier to do with Linq, which contains functions for grouping and summing.
List<jd_records> result = jddt.Rows
.GroupBy(jd => jd.invoiceNo)
.Select(jd => new jd_records
{
invoiceNo = jd.invoiceNo,
totalTax = jd.Sum(d => d.tax)
}).ToList();

Related

I have a "Upload Record" PXAction to load records to grid and release these records

I have a custom PXbutton called UploadRecords, when I click this button I should populate the grid with records and release the records.
Release Action is pressed in the UploadRecords action delegate. The problem I get with this code is, the code here function properly for less records by release action but when passes thousands of records to release, it takes huge time(> 30 min.) and show the error like Execution timeout.
suggest me to avoid more execution time and release the records fastly.
namespace PX.Objects.AR
{
public class ARPriceWorksheetMaint_Extension : PXGraphExtension<ARPriceWorksheetMaint>
{
//public class string_R112 : Constant<string>
//{
// public string_R112()
// : base("4E5CCAFC-0957-4DB3-A4DA-2A24EA700047")
// {
// }
//}
public class string_R112 : Constant<string>
{
public string_R112()
: base("EA")
{
}
}
public PXSelectJoin<InventoryItem, InnerJoin<CSAnswers, On<InventoryItem.noteID, Equal<CSAnswers.refNoteID>>,
LeftJoin<INItemCost, On<InventoryItem.inventoryID, Equal<INItemCost.inventoryID>>>>,
Where<InventoryItem.salesUnit, Equal<string_R112>>> records;
public PXAction<ARPriceWorksheet> uploadRecord;
[PXUIField(DisplayName = "Upload Records", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXButton]
public IEnumerable UploadRecord(PXAdapter adapter)
{
using (PXTransactionScope ts = new PXTransactionScope())
{
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in records.Select())
{
InventoryItem invItem = (InventoryItem)res;
INItemCost itemCost = (INItemCost)res;
CSAnswers csAnswer = (CSAnswers)res;
ARPriceWorksheetDetail gridDetail = new ARPriceWorksheetDetail();
gridDetail.PriceType = PriceTypeList.CustomerPriceClass;
gridDetail.PriceCode = csAnswer.AttributeID;
gridDetail.AlternateID = "";
gridDetail.InventoryID = invItem.InventoryID;
gridDetail.Description = invItem.Descr;
gridDetail.UOM = "EA";
gridDetail.SiteID = 6;
InventoryItemExt invExt = PXCache<InventoryItem>.GetExtension<InventoryItemExt>(invItem);
decimal y;
if (decimal.TryParse(csAnswer.Value, out y))
{
y = decimal.Parse(csAnswer.Value);
}
else
y = decimal.Parse(csAnswer.Value.Replace(" ", ""));
gridDetail.CurrentPrice = y; //(invExt.UsrMarketCost ?? 0m) * (Math.Round(y / 100, 2));
gridDetail.PendingPrice = y; // (invExt.UsrMarketCost ?? 0m)* (Math.Round( y/ 100, 2));
gridDetail.TaxID = null;
Base.Details.Update(gridDetail);
}
ts.Complete();
}
Base.Document.Current.Hold = false;
using (PXTransactionScope ts = new PXTransactionScope())
{
Base.Release.Press();
ts.Complete();
}
List<ARPriceWorksheet> lst = new List<ARPriceWorksheet>
{
Base.Document.Current
};
return lst;
}
protected void ARPriceWorksheet_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (ARPriceWorksheet)e.Row;
uploadRecord.SetEnabled(row.Status != SPWorksheetStatus.Released);
}
}
}
First, Do you need them all to be in a single transaction scope? This would revert all changes if there is an exception in any. If you need to have them all committed without any errors rather than each record, you would have to perform the updates this way.
I would suggest though moving your process to a custom processing screen. This way you can load the records, select one or many, and use the processing engine built into Acumatica to handle the process, rather than a single button click action. Here is an example: https://www.acumatica.com/blog/creating-custom-processing-screens-in-acumatica/
Based on the feedback that it must be all in a single transaction scope and thousands of records, I can only see two optimizations that may assist. First is increasing the Timeout as explained in this blog post. https://acumaticaclouderp.blogspot.com/2017/12/acumatica-snapshots-uploading-and.html
Next I would load all records into memory first and then loop through them with a ToList(). That might save you time as it should pull all records at once rather than once for each record.
going from
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in records.Select())
to
var recordList = records.Select().ToList();
foreach (PXResult<InventoryItem, CSAnswers, INItemCost> res in recordList)

Get Meteor collection object instance by name

I have seen similar questions but I think my scenario is a bit different. Say I define a collection like this:
MyCol = new Meteor.Collection("myCol"
and I want to get a reference to 'MyCol' using the string 'myCol' - I have created the function below which seems to work:
function GetCollectionObject(name) {
for(var key in window) {
var value = window[key];
if (value instanceof Meteor.Collection) {
if (value._name == name) {
return value;
break;
}
}
}
return null;
}
Is this the only/best/most efficient way to do this?
Why don't you store your collections in a dictionary? It's way more efficient.
Dogs = new Meteor.Collection('dogs');
Cats = new Meteor.Collection('cats');
Alpacas = new Meteor.Collection('alpacas');
MyCollections = {
dogs: Dogs,
cats: Cats,
alpacas: Alpacas,
};
...
MyCollections['dogs'].doSomething();

Blackberry app very slow why using Sqlite Queries in loop

I am working on bb app , app is complete but its very slow while selecting data from sqlite ,I am not able to find any solution to boost up the performance, please see code below
for(int a=0;a<200;a++){
retrieveCode(selectQuery);
}
where
public String retrieveCode(String query)
{
String s = "";
Vector v = new Vector();
try
{
g.vec_Result = new Vector();
// Read in all records from the Category table
Statement statement = _db.createStatement(query);//"SELECT * FROM samples"
statement.prepare();
Cursor cursor = statement.getCursor();
Row row;
// Iterate through the result set. For each row, create a new
// Category object and add it to the hash table.
while(cursor.next())
{
row = cursor.getRow();
s = row.getString(0);
v.addElement(vmd);
}
statement.close();
cursor.close();
}
catch(DatabaseException dbe)
{
g.errorDialog(dbe.toString());
}
catch(DataTypeException dte)
{
g.errorDialog(dte.toString());
}
s = v.firstElement().toString();
return s;
}
I am developing for OS5.0 , please help

Searching for a string in a single column in a table within an ASP.NET MVC application

I have a table named Orders that has a column named OrderCode that stores a string that I randomly generate at the time of creation.
I want to make sure this string (OrderCode) is unique before I save it to my table.
How I have attempted to do this:
bool isUnique = false;
var order = new Order();
var code = RandomCode.Generate();
while (isUnique == false) // checks to see if the code we generated is unique among all generated codes, if not, will generate another code
{
var activeOrders = storeDB.Orders.Find("OrderCode", code);
if (activeOrders == null)
{
isUnique = true;
}
else
{
code = RandomCode.Generate();
}
}
order.OrderCode = code;
The problem appears to be that the DbSet<TEntity>.Find Method is actually used to search through primary keys - but I am needing to search for a string that is not a primary key.
What is a correct approach to this situation?
if (context.Orders.Any(o => o.OrderCode == code))
{
// key found
}
if (context.Orders.FirstOrDefault(o => o.OrderCode == code) != null)
{
// key found
}
May I ask why you don't just use a System.Guid though (Guid.NewGuid().ToString())? This would virtually eliminate this kind of issue.

Flex: Sort -- Writing a custom compareFunction?

OK, I am sorting an XMLListCollection in alphabetical order. I have one issue though. If the value is "ALL" I want it to be first in the list. In most cases this happens already but values that are numbers are being sorted before "ALL". I want "ALL" to always be the first selection in my dataProvider and then the rest alphabetical.
So I am trying to write my own sort function. Is there a way I can check if one of the values is all, and if not tell it to do the regular compare on the values?
Here is what I have:
function myCompare(a:Object, b:Object, fields:Array = null):int
{
if(String(a).toLowerCase() == 'all')
{
return -1;
}
else
if(String(b).toLowerCase() == 'all')
{
return 1;
}
// NEED to return default comparison results here?
}
//------------------------------
var sort:Sort = new Sort();
sort.compareFunction = myCompare;
Is there a solution for what I am trying to do?
The solution from John Isaacks is awesome, but he forgot about "fields" variable and his example doesn't work for more complicated objects (other than Strings)
Example:
// collection with custom objects. We want to sort them on "value" property
// var item:CustomObject = new CustomObject();
// item.name = 'Test';
// item.value = 'Simple Value';
var collection:ArrayCollection = new ArrayCollection();
var s:Sort = new Sort();
s.fields = [new SortField("value")];
s.compareFunction = myCompare;
collection.sort = s;
collection.refresh();
private function myCompare(a:Object, b:Object, fields:Array = null):int
{
if(String((a as CustomObject).value).toLowerCase() == 'all')
{
return -1;
}
else if(String((b as CustomObject).value).toLowerCase() == 'all')
{
return 1;
}
// NEED to return default comparison results here?
var s:Sort = new Sort();
s.fields = fields;
var f:Function = s.compareFunction;
return f.call(null,a,b,fields);
}
Well I tried something out, and I am really surprised it actually worked, but here is what I did.
The Sort class has a private function called internalCompare. Since it is private you cannot call it. BUT there is a getter function called compareFunction, and if no compare function is defined it returns a reference to the internalCompare function. So what I did was get this reference and then call it.
private function myCompare(a:Object, b:Object, fields:Array = null):int
{
if(String(a).toLowerCase() == 'all')
{
return -1;
}
else if(String(b).toLowerCase() == 'all')
{
return 1;
}
// NEED to return default comparison results here?
var s:Sort = new Sort();
var f:Function = s.compareFunction;
return f.call(null,a,b,fields);
}
Thanks guys, this helped a lot. In our case, we needed all empty rows (in a DataGrid) on the bottom. All non-empty rows should be sorted normally. Our row data is all dynamic Objects (converted from JSON) -- the call to ValidationHelper.hasData() simply checks if the row is empty. For some reason the fields sometimes contain the dataField String value instead of SortFields, hence the check before setting the 'fields' property:
private function compareEmptyAlwaysLast(a:Object, b:Object, fields:Array = null):int {
var result:int;
if (!ValidationHelper.hasData(a)) {
result = 1;
} else if (!ValidationHelper.hasData(b)) {
result = -1;
} else {
if (fields && fields.length > 0 && fields[0] is SortField) {
STATIC_SORT.fields = fields;
}
var f:Function = STATIC_SORT.compareFunction;
result = f.call(null,a,b,fields);
}
return result;
}
I didn't find these approaches to work for my situation, which was to alphabetize a list of Strings and then append a 'Create new...' item at the end of the list.
The way I handled things is a little inelegant, but reliable.
I sorted my ArrayCollection of Strings, called orgNameList, with an alpha sort, like so:
var alphaSort:Sort = new Sort();
alphaSort.fields = [new SortField(null, true)];
orgNameList.sort = alphaSort;
orgNameList.refresh();
Then I copied the elements of the sorted list into a new ArrayCollection, called customerDataList. The result being that the new ArrayCollection of elements are in alphabetical order, but are not under the influence of a Sort object. So, adding a new element will add it to the end of the ArrayCollection. Likewise, adding an item to a particular index in the ArrayCollection will also work as expected.
for each(var org:String in orgNameList)
{
customerDataList.addItem(org);
}
Then I just tacked on the 'Create new...' item, like this:
if(userIsAllowedToCreateNewCustomer)
{
customerDataList.addItem(CREATE_NEW);
customerDataList.refresh();
}

Resources