Json to datatable with proper column data get from json - vb.net

My JSON data looks as shown below. Sometimes it's changed the Field Name Position. How to store this data into a Datatable and must be in proper column. Suggest any solution for VB.Net
<string xmlns="http://tecogis.com/">[
{
"REPORT NUMBER":"LG534248650",
"REPORT CITY DATE":"June 22, 2022",
"DESCRIPTION":"LABORATORY GROWN DIAMOND",
"SHAPE AND CUT":"ROUND BRILLIANT",
"CARAT WEIGHT":"1.07 Carat",
"COLOR GRADE":"D",
"CLARITY GRADE":"SI 2",
"CUT GRADE":"VERY GOOD",
"POLISH":"EXCELLENT",
"SYMMETRY":"EXCELLENT",
"Measurements":"6.41 - 6.44 x 4.10 mm",
"Table Size":"57%",
"Crown Height":"15.5% - 35.4°",
"Pavilion Depth":"43.5% - 41.1°",
"Girdle Thickness":"MEDIUM TO SLIGHTLY THICK (FACETED)",
"Culet":"POINTED",
"Total Depth":"63.9%",
"FLUORESCENCE":"NONE",
"COMMENTS":"As Grown - No indication of post-growth treatment\r\nThis Laboratory Grown Diamond was created by High Pressure High Temperature (HPHT) growth process\r\nType II\r\n",
"Inscription(s)":"LABGROWN IGI LG534248650\u003cbr\u003e",
"REPORT_SUF":"LEGAL",
"PDF_FLAG":"Y",
"REPORT1_PDF":"FDR534248650.pdf"
}
]</string>

This is the missing piece you need. Note that it's from my own project so just adjust accordingly for your situation.
Before this, you just need to create a List of your custom type, populate it from your JSON (see Hursey's answer) and reference it instead of BlogList from my code.
This code will then transfer the data from your List into a DataTable which is the DataSource for the DataGridView.
'Declare a DataTable:
Private BlogTable As New DataTable
'Through code, modify a DataGridView instance on your form and clear things:
dgvBlogs.Columns.Clear()
dgvBlogs.DataSource = Nothing
'Set up our columns in the DataTable:
BlogTable.Columns.Add("blogname")
BlogTable.Columns.Add("username")
BlogTable.Columns.Add("password")
dgvBlogs.AutoGenerateColumns = True
dgvBlogs.DataSource = BlogTable
'Put data from JSON into the DataSource:
BlogTable.Rows.Clear()
For Each item As BlogRecord In BlogList
Dim row As DataRow = BlogTable.NewRow()
row("blogname") = item.BlogName
row("username") = item.Username
row("password") = item.Password
BlogTable.Rows.Add(row)
Next
So, conceptually, it's like this:
JSON -> List Of(Your Class) -> DataTable -> DataGridView.DataSource
You turn your JSON into a list of whatever custom item type you want to call it. Then you populate a DataTable from that. And you be sure that your DataGridView.DataSource property is set to your DataTable.
This works for me. The only thing to add is double-check the AutoGenerateColumns because for some reason in my code first I set it to True and then later to False. I'm sure that was just me experimenting and I never cleaned it up.

Related

Power Builder 10.5 user object array to datawindow table

I am new to Power Builder and I would like to ask how can I represent my objects in a table form. For example, given an ArrayList in java I have implemented the code like this:
table = new JTable();
scrollPane.setViewportView(table);
DefaultTableModel tableModel =
new DefaultTableModel(
new String[] {
"ScheduleNo",
"Start Date",
"End Date",
"No of days",
"Principal Expected",
"Interest Expected",
"EMI amount",
"Factor",
"MeanFactor"}
, 0);
for (Schedule s : pf.getSchedules()){
Integer schNo = s.getScheduleNo();
String startDate = df.format(s.getStartDate());
String endDate = df.format(s.getEndDate());
Integer noofdays = s.getNoOfDays();
String prinExp = String.format("%.2f", s.getPrincipalAmt());
String intExp = String.format("%.2f", s.getInterestAmt());
String emi = String.format("%.2f", s.getAmortizedAmount());
String factor = String.format("%.6f", s.getFactor());
String mean = String.format("%.6f", s.getProductByFactor());
Object[]data = {schNo, startDate, endDate, noofdays, prinExp, intExp,
emi, factor, mean};
tableModel.addRow(data);
}
table.setModel(tableModel);
But I cannot find a way to do it in PowerBuilder without having a connection to a database and pick the data from there which is totally not the case.
The data come from an User Object array[] and have exactly the same form like in the Java example above.
Without really knowing what you are trying to accomplish it appears to me that you could use a 'normal' PowerBuilder datawindow but when you define it you make it's datasource as external. This type of datawindow does not require a connection to a database. You define the 'fields' of the datasource as strings, numeric, etc. when you create it.
In code you can create a datawindow (or datastore for that matter) control, assign the external datasource datawindow object to it, insert a row, then populate the fields with data of the corresponding datatype.
Example usage:
datawindow ldw
long llrow
ldw = CREATE datawindow
ldw.dataobject = 'myExternalDatawindowObject'
llrow = ldw.insertrow(0)
ldw.setitem(llrow,'stringcolumn','my example string')
ldw.setitem(llrow,'numericcolumn',1234)
It's been a while since I used PowerBuilder, but IIRC you should be able to use a DataStore without having a database connection.

Calling a function within Entity Framework Select

A property from my object (oJobs) is as follows:
Private _brandlist As List(Of DAL.Brand)
Public Property PostBrandList() As List(Of DAL.Brand)
Get
Return _brandlist
End Get
Set(ByVal value As List(Of DAL.Brand))
_brandlist = value
End Set
End Property
In the database, the brand list is stored as a string separated by comma e.g. the column 'brands' can be a string '3,45,2' where each number represents an id of a brand stored in another table.
my select query is as below:
Dim jobposts As List(Of oJobs) = From j In db.JobPostings
Select New oJobs With { 'hiding all others for code brevity
.PostBrandList = 'problem is here'
}
Since j.BrandList will return a string, I will need to split that string and for each number, run another query to finally return and assign a List(Of DAL.Brand) into .PostBrandList
For those who might ask "what have you tried?",
I have run the query, then did a for each to add the list of brands later - succeeded but not optimal
Coded a function that takes the list as a parameter and returns a separate list of objects - very silly.
Also, I am not allowed to normalize the DB :(
Not tested and might need some tweaking but heres one idea. you will also need to change your property to an IEnumerable rather than List. Because the second linq query is embedded within the first, I believe it should execute it all as one query, but you should check it to make sure.
Dim jobposts As List(Of oJobs) = From j In db.JobPostings
Select New oJobs With { 'hiding all others for code brevity
.PostBrandList = From b In db.Brands Where j.Brands = b.ID Or j.Brands.StartsWith(b.ID & ",") Or j.Brands.EndsWith("," & b.ID) Or j.Brands.Contains("," & b.ID & ",") Select b
}
In c# you can use
.Select(x=>new {x.BrandList})
.ToList() //Materialize first before calling function
.Select(x=> new oJobs{
PostBrandList =
db.Brands.Where(z=>
x.BrandList
.Split(',')
.Select(y=>int.Parse(y.Trim()))
.Contains(z.Id))
.ToList()
});
Note that you must materialize entity first before calling String.Split
I don't know how to translate that to VB.NET.
Of course it will cause SELECT n+1 problem because you can't use join.
If you can't normalize table, my other suggestion is to create indexed view (sql server), so you can use join and improve performance.
Indexed view https://msdn.microsoft.com/en-us/library/ms191432.aspx
You could try it with the Let statement:
Dim jobposts As List(Of oJobs) = From j In db.JobPostings
/* li in the LINQ Statement represents one string value from the BrandList list */
Let postBrandElemsList = j.BrandList.Split(',').Select(Function(li) New DAL.Brand With { ... /* Field initializatione of the Class DAL.Brand here */ }
Select New oJobs With
{
.PostBrandList = postBrandElemsList
}
I'm sorry for the probably bad VB.NET syntax, you should check this when implementing it in your code.
Maybe you would just want to use the Split function on the column brands into an array and iterate through the result, using the Find function to retrieve the brand objects?

How to disable validating row when it loses focus in Datagridview

I have a datagridview, and I would like to allow the end user to type whateever he wants in the rows and the validation will be done later programmatically.
For example
Column1 : AllowDBNull = true
The user will still be able skip the cell related to Column1 and move to another row (may be to fill it later)
And the validation will be performed once he clicks ValidateButton.
I have been looking to :
DataGridView.CausesValidation = False
But that was unsuccessful.
I was trying also
DataSourceUpdateMode = DataSourceUpdateMode.Never
but couldn't apply this property to DataGridView.Datasource
Here is a bit of my code
'CreateMasterDataTable and CreateDetailDataTable are two functions that return two datatables
Master_DT = CreateMasterDataTable()
Detail_DT = CreateDetailDataTable()
DataSet.Tables.Add(Master_DT)
DataSet.Tables.Add(Detail_DT)
DataSet.Relations.Add("Relation", Master_DT.Columns("City"), Detail_DT.Columns("City"))
Master_BindingSource.DataSource = DataSet
Master_BindingSource.DataMember = Master_DT.TableName
Details_BindingSource.DataSource = Master_BindingSource
Details_BindingSource.DataMember = "Relation"
DataGridView.DataSource = Details_BindingSource
Does anyone have an idea on how to disable the row validation once it loses focus please ?
Thanks

Sorting List(Of MaskedTextBox)

The list Private msklistclass1 As New List(Of MaskedTextBox) contains following MaskedTextBox controls after executing the following code
For Each ctrl As Control In Me.pnlclass11.Controls
If TypeOf ctrl Is MaskedTextBox Then
msklistclass1.Add(ctrl)
End If
Next
seat112
seat212
seat312
seat412
seat512
seat612
seat122
seat222
seat322
seat422
seat522
seat622
but they aren't in the order I have shown above I suppose. When I try to assign values to these controls in a sequential manner they don't get assigned in an order.
I tried the following code
For i = 0 To 11 Step 1
msklistclass1(i).Text = rno312(i)
Next
The assignment I expect is
seat112 1138M0321
seat212 1138M0322
seat312 1138M0323
seat412 1138M0324
seat512 1138M0325
seat612 1138M0326
But they aren't getting assigned in this order
Is there a possibility to sort the list msklistclass1
This line gives me the following output msklistclass1.Sort(Function(x, y) x.Name.CompareTo(y.Name))
seat111 1138M0321 seat121 1138M0321
seat211 1138M0323 seat221 1138M0324
seat311 1138M0325 seat321 1138M0326
seat411 1138M0326 seat421 1138M0327
seat511 1138M0328 seat521 1138M0329
seat611 1138M0330 seat621 1138M0331
but I want
seat111 1138M0321 seat121 1138M0327
seat211 1138M0322 seat221 1138M0328
seat311 1138M0323 seat321 1138M0329
seat411 1138M0324 seat421 1138M0330
seat511 1138M0325 seat521 1138M0331
seat611 1138M0326 seat621 1138M0332
Using LINQ, you can do this:
Dim listOrdered = From m In msklistclass1 Order By m.Text
Or if you cannot use LINQ or do not want to, then do this:
msklistclass1.Sort(Function(x, y) x.Name.CompareTo(y.Text))
Note: If you want to sort by a different property of the MaskedTextBox, then just change Text to whatever the property name is, like Name for instance.

Issue with itextsharp

I have a PDF document that has several hundred fields. All of the field names have periods in them, such as "page1.line1.something"
I want to remove these periods and replace them with either an underscore or (better) nothing at all
There appears to be a bug in the itextsharp libraries where the renamefield method does not work if the field has a period, so the following does not work (always returns false)
Dim formfields As AcroFields = stamper.AcroFields
Dim renametest As Boolean
renametest = formfields.RenameField("page1.line1.something", "page1_line1_something")
If the field does not have a period in it, it works fine.
Has anyone come across this and is there a workaround?
Is this an AcroForm form or a LiveCycle Designer (xfa) form?
If it's XFA (which is likely given the field names), iText can't help you. It can only get/set field values when working with XFA.
Okay, an AcroForm. Rather than go the route used in your source, I suggest you directly manipulate the existing field dictionaries and the acroForm field list.
I'm a Java native when it comes to iText, so you'll have to do some translation, but here goes:
A) Delete the AcroForm's field array. Leave the calculation order alone if present (/CO). I think.
PdfDictionary acroDict = reader.getCatalog().getAsDictionary(PdfName.ACROFORM);
acroDict.remove(PdfName.FIELDS);
B) Attach all the 'top level' fields to a new FIELDS array.
PdfArray newFldArray = new PdfArray();
acroDict.put(newFldArray, PdfName.FIELDS);
// you could wipe this between pages to speed things up a bit
Set<PdfIndirectReference> radioFieldsAdded = new HashSet<PdfIndirectReference>();
int numPages = reader.getNumberOfPages();
for (int curPg = 1; curPg <= numPages; ++curPg) {
PdfDictionary curPageDict = reader.getPageN(curPg);
PdfArray annotArray = curPageDict.getAsArray(PdfName.ANNOTS);
if (annotArray == null)
continue;
for (int annotIdx = 0; annotIdx < annotArray.size(); ++annotIdx) {
PdfIndirectReference fieldReference = (PdfIndirectReference) annotArray.getAsIndirect(annotIdx);
PdfDictionary field = (PdfDictionary)PdfReader.getObject(fieldReference);
// if it's a radio button
if ((PdfFormField.FF_RADIO & field.getAsNumber(PdfName.FF).intValue()) != 0) {
fieldReference = field.get(pdfName.PARENT);
field = field.getAsDict(PdfName.PARENT); // looks up indirect reference for you.
// only add each radio field once.
if (radioFieldsAdded.contains(fieldReference)) {
continue;
} else {
radioFieldsAdded.add(fieldReference);
}
}
field.remove(PdfName.PARENT);
// you'll need to assemble the original field name manually and replace the bits
// you don't like. Parent.T + '.' child.T + '.' + ...
String newFieldName = SomeFunction(field);
field.put(PdfName.T, new PdfString( newFieldName ) );
// add the reference, not the dictionary
newFldArray.add(fieldReference)
}
}
C) Clean up
reader.removeUnusedObjects();
Disadvantage:
More Work.
Advantages:
Maintains all field types, attributes, appearances, and doesn't change the file as a whole all that much. Less CPU & memory.
Your existing code ignores field script, all the field flags (read only, hidden, required, multiline text, etc), lists/combos, radio buttons, and quite a few other odds and ends.
if you use periods in your field name, only the last part can be renamed, e.g. in page1.line1.something only "something" can be renamed. This is because the "page1" and "line1" are treated by adobe as parents to the "something" field
I needed to delete this hierarchy and replace it with a flattened structure
I did this by
creating a pdfdictionary object for each field
reading the annotations I needed for each field into an array
deleting the field hierarchy in my (pdfstamper) document
creating a new set of fields from my array data
I have created some sample code for this if you want to see how I did it.