Read callback data in new thread C# - multithreading

Can someone help me, I have one method that I call to "activate" callback method(which is set to send me changed data every second) and second method(which is "activated" by first) that runs every second and give me data. That is all fine, but I need that second method run in new thread and after couple days of trying and reading I couldn't mange to do that. Can someone please guide me how to do that? here is my code.
int ItemNumItems;
Array ItemClientHandles;
Array ItemServerValues;
Array ItemQualities;
Array ItemTimeStamps;
public void Callback()
{
//Here I add a delegate with method to be called on data change.
Grupa1.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(Grupa1_DataChange);
}
void Grupa1_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
//Here I read my data and pass them to my variables(and this is
//runned every second) and I want this method to run in new thread.
ItemNumItems = NumItems;
ItemClientHandles = ClientHandles;
ItemServerValues = ItemValues;
ItemQualities = Qualities;
ItemTimeStamps = TimeStamps;
}

Something like that maybe:
void Grupa1_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
Array tmpClientHandles = ClientHandles;
Array tmpItemValues = ItemValues;
Array tmpQualities = Qualities;
Array tmpTimeStamps = TimeStamps;
ThreadPool.QueueUserWorkItem(o =>
{
//Here I read my data and pass them to my variables(and this is
//runned every second) and I want this method to run in new thread.
ItemNumItems = NumItems;
ItemClientHandles = tmpClientHandles;
ItemServerValues = tmpItemValues;
ItemQualities = tmpQualities;
ItemTimeStamps = tmpTimeStamps;
});
}
?
But why to you want to run it asynchronously?
From the code you show there is nothing that will gain to being run in parallel.

Related

NODE.JS: iterating over an array of objects, creating a new key if it does not exist

I am iterating over a collection of data, in my case, an array of objects. Here is a sample of 2 data points from it:
{
violation_id: '211315',
inspection_id: '268804',
violation_category: 'Garbage and Refuse',
violation_date: '2012-03-22 0:00',
violation_date_closed: '',
violation_type: 'Refuse Accumulation' },
{
violation_id: '214351',
inspection_id: '273183',
violation_category: 'Building Conditions',
violation_date: '2012-05-01 0:00',
violation_date_closed: '2012-04-17 0:00',
violation_type: 'Mold or Mildew' }
I need to create a new array of objects from this, one for each "violation_category" property. If Violation category already exists in the new array I am creating, i simply add the information to that existing category object (instead of having two "building conditions" objects for example, I would just add to an existing one).
However, I am having trouble assigning to the existing object if the current one exists (it's easy to check if it does not, but not the other way around). This is what am attempting to do currently:
if (violationCategory.uniqueCategoryName) {
violationCategory.uniqueCategoryName.violations = results[i].violation_id;
violationCategory.uniqueCategoryName.date = results[i].violation_date;
violationCategory.uniqueCategoryName.closed =
results[i].violation_date_closed;
} else {
category.violations = results[i].violation_id;
category.date = results[i].violation_date;
category.closed = results[i].violation_date_closed;
violationCategory.push(category);
}
In first condition, if this category (key) exists, I simply add to it, and in the second condition, this is where I am struggling. Any help appreciated. Thanks guys.
Just add an empty object to the key if there no object there :
violationCategory.uniqueCategoryName = violationCategory.uniqueCategoryName || {};
And only then, add the data you want to the object.
violationCategory.uniqueCategoryName.violations = results[i].violation_id;
violationCategory.uniqueCategoryName.date = results[i].violation_date;
violationCategory.uniqueCategoryName.closed =
results[i].violation_date_closed;
No condition needed.
Good luck!
Assuming that you have an input variable which is an array of objects, where the objects are looking like the objects of the question, you can generate your output like this:
var output = {};
for (var item of input) {
if (!output[item.violation_category]) output[item.violation_category] = [];
output[item.violation_category].push(item);
}
Of course you might customize it like you want.

How to sort a Data delegate array

I am populating data using 2 views inside a data delegate. I have to calculate running balance by sorting the based on transaction date. How do i sort the data and populate the running balance.
The delegate code is given below.
[PXVirtualDAC]
public PXSelectOrderBy<FundBalanceData, OrderBy<Asc<FundBalanceData.tranDate>>> fbdata;
protected virtual IEnumerable FBData()
{
List<FundBalanceData> importlist = new List<FundBalanceData>();
PXSelectBase<ARPayment> cmd = new PXSelectJoin<ARPayment, InnerJoin<GLTran, On<ARPayment.batchNbr, Equal<GLTran.batchNbr>>,
InnerJoin<PMProject, On<GLTran.projectID, Equal<PMProject.contractID>>>>,
Where<GLTran.projectID, Equal<Current<PMProject.contractID>>,
And<ARPayment.docType, Equal<ARPaymentType.prepayment>>>>(Base);
foreach(PXResult<ARPayment,GLTran,PMProject> line in cmd.Select())
{
FundBalanceData data = new FundBalanceData();
ARPayment arp = line;
PMProject pmp = line;
GLTran glt = line;
data.BAccountID = arp.CustomerID;
data.CreditAmount = glt.CreditAmt;
data.DebitAmount = glt.DebitAmt;
data.RefNbr = arp.RefNbr;
data.DocType = arp.DocType;
data.Desc = arp.DocDesc;
data.TranDate = arp.DocDate;
importlist.Add(data);
}
PXSelectBase<APAdjust> cmd2 = new PXSelectJoin<APAdjust, LeftJoin<GLTran, On<APAdjust.adjBatchNbr, Equal<GLTran.batchNbr>, And<APAdjust.adjdAPAcct, Equal<GLTran.accountID>>>,
InnerJoin<APPayment, On<APAdjust.adjgRefNbr, Equal<APPayment.refNbr>, And<APAdjust.adjgDocType, Equal<APPayment.docType>>>,
InnerJoin<APTran,On<APTran.refNbr,Equal<APAdjust.adjdRefNbr>,And<APTran.tranType,Equal<APAdjust.adjdDocType>>>>>>,
//InnerJoin<GLTran, On<APTran.projectID, Equal<GLTran.projectID>>>>>,
Where<APAdjust.adjgDocType, Equal<APPaymentType.prepayment>, And<APTran.projectID, Equal<Current<PMProject.contractID>>, And<GLTran.accountID, NotEqual<APPayment.aPAccountID>>>>>(Base);
foreach (PXResult<APAdjust,GLTran,APPayment,APTran> line in cmd2.Select())
{
FundBalanceData data = new FundBalanceData();
APPayment arp = line;
GLTran glt = line;
APAdjust apd = line;
data.BAccountID = arp.VendorID;
data.CreditAmount = glt.CreditAmt;
data.DebitAmount = glt.DebitAmt;
data.RefNbr = arp.RefNbr;
data.DocType = arp.DocType;
data.Desc = arp.DocDesc;
data.TranDate = arp.DocDate;
importlist.Add(data);
}
decimal? balance = decimal.Zero;
foreach(FundBalanceData data in importlist)
{
balance = balance + (data.CreditAmount - data.DebitAmount);
data.Balance = balance;
}
return importlist;
}
The array is not sorted by TranDate and the balance calculated is wrong
The result after implementing Samvel Petrosov suggestion
I was trying to sort the array on DateTime? and missed used the Value property. I have tried Samvel Petrosov suggestion and it worked.
Here is the part about sorting of the Result set of data views from T200 Acumatica Framework Fundamentals Course:
A data view executes the delegate by the following rules:
If a delegate is defined, invoke the delegate
If the delegate returns null, execute the BQL command
If the delegate returns an object, reorder the result according to the OrderBy clause of the BQL command
If a delegate is not defined, execute the BQL command
The result set returned by the data view is always sorted by the ORDER
BY clause specified in the type of the data view object. If you sort
data records in a different way within the delegate, the result set
will be reordered before it is returned by the data view.
The calculation of the Balance in your code is done before the return of the result set. That is way it is not calculated as you are waiting. The sorting is taking place after you return the result set.
UPDATE 1
Change your cmd and cmd2 to the following queries:
PXSelectBase<ARPayment> cmd = new PXSelectJoin<ARPayment, InnerJoin<GLTran, On<ARPayment.batchNbr, Equal<GLTran.batchNbr>>,
InnerJoin<PMProject, On<GLTran.projectID, Equal<PMProject.contractID>>>>,
Where<GLTran.projectID, Equal<Current<PMProject.contractID>>,
And<ARPayment.docType, Equal<ARPaymentType.prepayment>>>,OrderBy<Asc<ARPayment.DocDate>>>(Base);
PXSelectBase<APAdjust> cmd2 = new PXSelectJoin<APAdjust, LeftJoin<GLTran, On<APAdjust.adjBatchNbr, Equal<GLTran.batchNbr>, And<APAdjust.adjdAPAcct, Equal<GLTran.accountID>>>,
InnerJoin<APPayment, On<APAdjust.adjgRefNbr, Equal<APPayment.refNbr>, And<APAdjust.adjgDocType, Equal<APPayment.docType>>>,
InnerJoin<APTran,On<APTran.refNbr,Equal<APAdjust.adjdRefNbr>,And<APTran.tranType,Equal<APAdjust.adjdDocType>>>>>>,
//InnerJoin<GLTran, On<APTran.projectID, Equal<GLTran.projectID>>>>>,
Where<APAdjust.adjgDocType, Equal<APPaymentType.prepayment>, And<APTran.projectID, Equal<Current<PMProject.contractID>>, And<GLTran.accountID, NotEqual<APPayment.aPAccountID>>>>,OrderBy<Asc<APPayment.DocDate>>>(Base);
UPDATE 2
Try to add additional sorting by transaction date before the last loop:
importlist= importlist.OrderBy(x => x.TranDate.Value).ToList();
or if TranDate is not DateTime?
importlist= importlist.OrderBy(x => x.TranDate).ToList();

Map to hold multiple sets of key and values

I have a map1 which holds the information as
[40256942,6] [60246792,5]
Now that I want to prepare a map2 that holds information such as
itemNo, 40256942
qty, 6
itemNo, 60246792
qty, 5
to prepare final information as json
“partialArticlesInfo”: [{itemNo:”40256942”, availQty:”6”}, {itemNo:”60246792”, availQty:”5”}]
I am trying to iterate map1 to retrieve values and set that against the key. But I am getting only one entry which is last one. Is there any way , I get the new map with entries such as mentioned above
Map<String, String> partialArticlesInfo = new HashMap<String,String>();
Map<String, String> partialArticlesTempMap = null;
for (Map.Entry<String,String> entry : partialStockArticlesQtyMap.entrySet())
{
partialArticlesTempMap = new HashMap<String,String>();
partialArticlesTempMap.put("itemNo",entry.getKey());
partialArticlesTempMap.put("availQty",entry.getValue());
partialArticlesInfo.putAll(partialArticlesTempMap);
}
In Java (I'm assuming you're using Java, in the future it would be helpful to specify that) and every other language I know of, a map holds mappings between keys and values. Only one mapping is allowed per key. In your "map2", the keys are "itemNo" and "availQty". So what is happening is that your for loop sets the values for the first entry, and then is overwriting them with the data from the second entry, which is why that is the only one you see. Look at Java - Map and Map - Java 8 for more info.
I don't understand why you are trying to put the data into a map, you could just put it straight into JSON with something like this:
JSONArray partialArticlesInfo = new JSONArray();
for (Map.Entry<String,String> entry : partialStockArticlesQtyMap.entrySet()) {
JSONObject stockEntry = new JSONObject();
stockEntry.put("itemNo", entry.getKey());
stockEntry.put("availQty", entry.getValue());
partialArticlesInfo.put(stockEntry);
}
JSONObject root = new JSONObject();
root.put("partialArticlesInfo",partialArticlesInfo);
This will take "map1" (partialStockArticlesQtyMap in your code) and create a JSON object exactly like your example - no need to have map2 as an intermediate step. It loops over each entry in map1, creates a JSON object representing it and adds it to a JSON array, which is finally added to a root JSON object as "partialArticlesInfo".
The exact code may be slightly different depending on which JSON library you are using - check the docs for the specifics.
I agree with Brendan. Another solution would be otherwise to store in the Set or List objects like the following.
class Item {
Long itemNo;
int quantity;
public int hashCode() {
Long.hashCode(itemNo) + Integer.hashCode(quantity);
}
public int equals(Object other) {
other instanceOf Item && other.itemNo == this.itemNo && other.quantity = this.quantity;
}
}
}
then you can use the JsonArray method described by him to get the Json string in output
This means that adding new variables to the object won't require any more effort to generate the Json

nodejs loop in asynch

Im sending user information to user when he signs in.
var userstuff00 = findSub(user['id']);
userstuff00.then(function(sub){
for(var i in sub){
var userstuff01 = findSub(sub[i.toString()]['id']);
userstuff01.then(function(sub2){
for(var i2 in sub2){
//here i is the last object in sub but i2 is for the first i
console.log(sub[i.toString()]);
console.log(sub2[i2.toString()]);
}
});
}
});
and this is findSub function where usercollection is mongodb table:
function findSub(stuffCode){
var tempMembers = usercollection.find({'stuff ': stuffCode});
return tempMembers;
}
this is user object :
user{
id,
name,
stuff,
subMember[] //list of users where their stuff equals to this users id
}
I want to add every sub2 in that users subMember but i's id is not equal to i2's stuff( I cant add i2 in another i's submember).
how can get submembers for the first i and then find submembers for the second i?
my goal is a list of users that has users as submembers and these users(submembers level 1) have submembers(submembers level 2) and so on (up to level 10) :
Family Tree
This is a typical issue when working with asynchronous code: the synchronous code will finish before any of the asynchronous code. So this loop:
for(var i in sub)
... will finish before any of the then callbacks inside it will be executed. So by the time one of those gets executed, the value of i is already the length of sub.
To be able to use the value of the i at the time you called then (not its callback), there are different solutions. One of them is to use let i instead of var i as it will define a different variable on each iteration of the for loop. Or you can bind the value of i as argument to the then callback:
userstuff01.then(function(i, sub2){
// ^^^ added parameter
for(var i2 in sub2){
//here i is the last object in sub but i2 is for the first i
console.log(sub[i.toString()]);
console.log(sub2[i2.toString()]);
}
}.bind(null, i));
// ^^^^^^^^^^^ bind the parameter value to the current value of i.

Returning an Object[][] gives NullPointerException

I have an Access database which I need to retrieve all fields except the first and last and display it in a JTable. Everything works perfectly fine when I create my Object[][] but when i return it, i get a NullPointerException. I tried to find where there could be a null value in the database by printing the whole object out but that works fine and no values are null. Why would returning the Object[][] give me a NullPointerException and how can i fix it?
the stack trace is:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
public Object [] [] SetTrainingLogTable() throws SQLException
{
DatabaseConnection connection = new DatabaseConnection();
//Retrieves all the data from the TrainingLog table
ResultSet resultset = connection.SelectStatements("SELECT * FROM TrainingLog");
//Retrieves the number of entries
ResultSet numberofworkouts = connection.SelectStatements("SELECT COUNT(*) FROM TrainingLog");
int count = numberofworkouts.getInt(1);
number = count;
String[][] table = new String [count] [6];
//Number to incriment for while loops
int row = 0;
String date = "";
while(row<count)
{
date = resultset.getString(2);
table [row][0] = calculate.RefineDate(date);
table [row][1] = resultset.getString(3);
table [row][2] = resultset.getString(4);
table [row][3] = resultset.getString(5);
table [row][4] = resultset.getString(6);
table [row][5] = resultset.getString(7);
resultset.next();
row++;
}
Object[][] data = table;
connection.close();
return data;
}
I ran a debugger and it only gives the error when the return line is run.
It's best to post the stack trace and tell which line is raising the error. However, the typical way of writing such code is:
Connection con = ...;
Statement st = ...;
ResultSet rs = ...;
while (rs.next()) {
// ...
}
The result set starts out pointing before the first row. rs.next() returns whether there is a next row, and advances to it if it exists. Can you rewrite it in that style?
Other suggestions:
Can you create an actual object type instead of using Object[] to store the data from each row? Call it Workout.
Can you use a List<Workout> instead of your Object[][]?
Is the date stored in the database as a SQL DATE or TIMESTAMP? Then, don't convert it to a Java String: use java.sql.Date or java.util.Date. At work, I have a large old program that uses strings for dates, and it uses different formats to convert the values at different times. It's pretty miserable.
Don't use SELECT *. Give the names of the columns to return. Use the rs.getString("column_name") syntax.
There's no need to set one variable to the returned table and immediately set another variable to it.
Closing the connection or statement should be done in a finally block, or by try-with-resources.

Resources