Unexpected JSON token when reading DataTable. Expected StartArray, got StartObject - c#

I have a valid json (any json string) string and trying to convert it to Dataset but Newtonsoft.Json failed to do so.
Json text:
{"root": {
"Item": [
{
"Name": "Super Mario Bros",
"Count": "14",
"Price": "29,99",
"Comment": "-No Comment-",
"Artist": "N/A",
"Publisher": "Nintendo",
"Genre": "Video Games",
"Year": "1985",
"ProductID": "001"
},
{
"Name": "The Legend of Zelda",
"Count": "12",
"Price": "34,99",
"Comment": "-No Comment-",
"Artist": "N/A",
"Publisher": "Nintendo",
"Genre": "Video Games",
"Year": "1986",
"ProductID": "002"
}
]
}
}
Code:
var table = JsonConvert.DeserializeObject<DataSet>(jsonText);
Error:
Unexpected JSON token when reading DataTable. Expected StartArray, got StartObject. Path 'root', line 1, position 9.
Edit 1:
user can pass any type of json and i need to convert it to DataSet
for the above example "root" element can contain any other property
like "child1":"val1", "child2":"val2" and so forth. so, the output
dataset will contain 2 tables namse root(should have one rows of
properties 1 and 2) and item(should have 2 rows of type name,count,price
etc).

It is not working because the JSON object representing the DataSet is not at the root level of the JSON. In your JSON, it is inside a property called root, which is inside another wrapper object. So you will need to take that outer object into account when you deserialize. You can either define a wrapper class and deserialize into that:
public class Wrapper
{
[JsonProperty("root")]
public DataSet DataSet { get; set; }
}
Then:
DataSet ds = JsonConvert.DeserializeObject<Wrapper>(json).DataSet;
(Fiddle)
Or, if you don't want to make a class, you can instead deserialize into a JObject, navigate down to the root property and then materialize it to a DataSet from there:
DataSet ds = JObject.Parse(json)["root"].ToObject<DataSet>();
(Fiddle)

The Json you showed is invalid.
It should look like this, to be load to the DataSet:
{
"Item": [
{
"Name": "Super Mario Bros",
"Count": "14",
"Price": "29,99",
"Comment": "-No Comment-",
"Artist": "N/A",
"Publisher": "Nintendo",
"Genre": "Video Games",
"Year": "1985",
"ProductID": "001"
},
{
"Name": "The Legend of Zelda",
"Count": "12",
"Price": "34,99",
"Comment": "-No Comment-",
"Artist": "N/A",
"Publisher": "Nintendo",
"Genre": "Video Games",
"Year": "1986",
"ProductID": "002"
}
]
}
Code:
var dataSet = JsonConvert.DeserializeObject<DataSet>(jsonText);
var table = dataSet.Tables[0];

just add [] while stringifying the object:
JSON.stringify([this.YourModel])

Related

Select type object from json?

I have a problem with correct parse object from json query. I read something about JObject. Now i have two Model for example like Car and MotorBike. Query result is:
"Vehicles":
[
{
"Id": 1,
"title": "test",
"price": "4000",
"type": "Car"
},
{
"Id": 1,
"title": "test",
"price": "4000",
"drivingLicenseCat" "A",
"type": "MotorBike"
}
]
how can i parse to custom model by type
How much control over the JSON do you have? If you are generating the JSON out of, say, web api correctly, it would come through more like:
"Vehicles":
[
{
"Id": 1,
"title": "test",
"price": "4000",
"$type": "YourNamespace.Car, YourNamespace"
},
{
"Id": 1,
"title": "test",
"price": "4000",
"drivingLicenseCat" "A",
"$type": "YourNamespace.MotorBike, YourNamespace"
}
]
and then it would be automatically deserialized when you bring it in...
Ensure, in the model that you are serializing and sending out as JSON, that you mark it up like so:
[JsonProperty(ItemTypeNameHandling = TypeNameHandling.All)]
This will add the type names to the objects as they are serialized. I should also note, that this is with Newtonsoft as your Json library. I'm not sure about the built-in Json.

SqlBulkCopy for datatables having inner datatables in c# console application

I have a datatable with 15 columns out of which 2 columns contain inner datatables containing 5 columns each. Is it possible to break hierarchy and add inner datatable columns to main datatable columns?
Or can I seperate those 2 columns from datatable and load them into different sql server table?
Inner datatables are formed by reading JSONArray object with multiple values.
I use following code part to Deserialize JSON into Datatable
var dtset = JsonConvert.DeserializeObject<DataTable>(JSON);
My JSON looks like below,
[{
"cpty": "SG, LP",
"internallegalentity": "ABC, LN",
"createdate": null,
"paymentcurrency": "USD",
"id": 123,
"version": 1,
"revisiondate": "2020-01-31 12:33:39.714",
"amount": -4.25,
"duedate": "2020-01-29",
"asofdate": "2020-02-25",
"isdeleted": false,
"source": "XYZ",
"isprovisional": null,
"isproforma": null,
"items": [{
"id": 123,
"amount": -4.25,
"currency": "USD",
"itemid": 15505,
"quantity": 1600.0,
"unit": "MWh",
"enddate": "2020-02-29",
"startdate": "2020-02-01",
"transactiondate": "2020-01-29",
"description": "Cash",
"price": 1.0
}],
"payments": [{
"createdate": "2020-02-12T00:00:00Z",
"transactiondate": "2020-02-11T12:00:00Z",
"paymentmethod": "Check",
"amount": 100.0,
"paymentcurrency": "USD",
"id": 123
},
{
"createdate": "2020-02-12T00:00:00Z",
"transactiondate": "2020-02-12T11:30:00Z",
"paymentmethod": "Check",
"amount": 100.0,
"paymentcurrency": "USD",
"id": 123
}
]
},
{
"counterparty": "AU",
"internallegalentity": "xyc, LP",
"createdate": null,
"paymentcurrency": "USD",
"id": 125,
"version": 1,
"revisiondate": "2020-01-31 12:33:39.922",
"amount": -5120.0,
"duedate": "2020-01-30",
"asofdate": "2020-02-25",
"isdeleted": false,
"source": "XYZ",
"isprovisional": null,
"isproforma": null,
"items": [{
"id": 125,
"amount": -1280.0,
"currency": "USD",
"itemid": 15508,
"quantity": 64000.0,
"unit": "MWh",
"enddate": "2021-02-28",
"startdate": "2021-01-01",
"transactiondate": "2020-01-30",
"description": "Cash",
"price": 1.0
},
{
"id": 125,
"amount": -1280.0,
"currency": "USD",
"itemid": 15507,
"quantity": 64000.0,
"unit": "MWh",
"enddate": "2021-02-28",
"startdate": "2021-01-01",
"transactiondate": "2020-01-30",
"description": "Cash",
"price": 1.0
}
]
}
]
Is there any way to read above JSON in more approprate way?
I'm assuming the real struggle you're having is not so much about the bulk copy aspect per se, but about flattening out the datatables. So aside from some simple code at the end, I'll really focus on that problem.
By the way, this is how you represent json in c# (fill in the elipsies of course):
static string json = #"
[
{
""cpty"": ""SG, LP"",
""internallegalentity"": ""ABC, LN"",
""createdate"": null,
""paymentcurrency"": ""USD"",
""id"": 123,
""version"": 1,
...
},
...
]";
First, create three DataTable variables. The first is your parsed json data, the other two are empty ones to receive your items and payments data:
DataTable jsonTable = JsonConvert.DeserializeObject<DataTable>(json);
DataTable items = null;
DataTable payments = null;
Next, loop through your parsed json data and extract your nested datatables into their variable counterparts. On the first pass, you'll want to copy the tables into their respective variables. On subsequent passes, you'll want to merge the tables into the variables. And be careful for the DBNull result in your payments field.
foreach (DataRow row in jsonTable.Rows) {
// get the inner "items"
var jsonItems = (DataTable)row["items"];
if (items == null)
items = jsonItems.Copy(); // first pass
else
items.Merge(jsonItems); // subsequent passes
// there is a null payments record, ignore it
if (row["payments"] == DBNull.Value)
continue;
// get the inner payments
var jsonPayments = (DataTable)(row["payments"]);
if (payments == null)
payments = jsonPayments.Copy(); // first not null pass
else
payments.Merge(jsonPayments); // subsequent passes
}
Now that you have the items and payments tables, delete those fields from your originally parsed table:
jsonTable.Columns.Remove("items");
jsonTable.Columns.Remove("payments");
You are now ready to bulk copy as appropriate. The following untested code assumes you already have existing tables with columns in the same order as your datatable representations.
using (var bulkcopy = new SqlBulkCopy("connection string")) {
bulkcopy.DestinationTableName = "main";
bulkcopy.WriteToServer(jsonTable);
bulkcopy.DestinationTableName = "items";
bulkcopy.WriteToServer(items);
bulkcopy.DestinationTableName = "payments";
bulkcopy.WriteToServer(payments);
}

Transform a JSON object to a JSON array, taking the first level of properties

I've this JSON object
{
"08f4f705-6e14-4781-8241-d04bf2dc6ada": {
"description": "xxxxxxxx",
"note": "yyyyyyyy"
},
"05f4f995-6e14-4567-8241-d04bf2d456ee": {
"description": "aaaaaa",
"note": "bbb"
},
"0675f995-6e14-4567-8241-d4567f2d456z": {
"description": "fffff",
"note": "gggg"
}
}
I need to convert into a JSON array like this:
(the elements should be the content of the first level properties)
[
{
"description": "xxxxxxxx",
"note": "yyyyyyyy"
},
{
"description": "aaaaaa",
"note": "bbb"
},
{
"description": "fffff",
"note": "gggg"
}
]
I can't manipulate the object and I didn't find an appropriate resource to follow. How can I do it?
You can achieve this by deserializing your json string into Dictionary<string, object>:
var obj = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
After that you extract the values and serialize them back to json:
var newJson = JsonConvert.SerializeObject(obj.Values);

How can I push an array into aggregate pipeline and pull it one level up?

I am new in MongoDB and I am developing a software by C# and MongoDB. My data structure is like this
{
"Id": 1,
"Title": "myTitle",
"Geners": [ "Drama", "Action" ],
"Category": 1,
"Casts": [
{
"Id": 1,
"Name": "myName",
"Gender": "Male",
"Age": 35
},
{
"Id": 2,
"Name": "herName",
"Gender": "Female",
"Age": 30
},
{
"Id": 3,
"Name": "hisName",
"Gender": "Male",
"Age": 45
}
]
}
This is just one document and I have about 5 million documents. I want to run a query like below to count the records based on Category and shows me how many movie do I have in each category and I want to put Casts field in result.
db.getCollection('myCollection').aggregate([
{
$group:{"_id":"$Category", "count": {$sum:1},
"Casts":{$push:"$Casts"}}
}
])
this is close to something I want but the problem is, it puts Casts data in second level of array like {"Id":1, ... , "Casts":[[{},{},...]]} but I need it like this {"Id":1, ... , "Casts":[{},{},...]}
How can I show the data like that?
If duplicates are acceptable, then the following aggregation will suffice:
db.getCollection('myCollection').aggregate([
{ $unwind:"$Casts"},
{
$group:{"_id":"$Category", "count": {$sum:1},
"Casts":{$push:"$Casts"}}
}
])
Update:
Since you need the count to be valid, there's a few more hoops to jump through.
db.getCollection('myCollection').aggregate([
{ $group:{"_id":"$Category", "count": {$sum:1}, "Casts":{$addToSet:"$Casts"}}},
{$unwind:"$Casts"},
{$unwind:"$Casts"},
{ $group:{"_id":"$_id", "count": {$first:"$count"}, "Casts":{$addToSet:"$Casts"}}},
])
Let me know if that helps

How to extract ID from the following JSON Object in C#?

I want to extract all IDs from the below object using c#.
in need of extracting a response value in a visual studio webtest.
The JSON is obtained using extract event.
{
"d": [
{
"__type": "QuestionZoneEditor.Entities.QuestionTag",
"Id": 2080,
"Name": "01",
"Items": [
"1a",
"1b",
"1c",
"1d"
]
},
{
"__type": "QuestionZoneEditor.Entities.QuestionTag",
"Id": 2081,
"Name": "02",
"Items": [
"2a(i)",
"2a(ii)",
"2b",
"2c"
]
},
{
"__type": "QuestionZoneEditor.Entities.QuestionTag",
"Id": 2082,
"Name": "03",
"Items": [
"3a",
"3b",
"3c"
]
}
}
]
}
Deserialize it to JObject after that take all JObject from the JArray and print the Id
var result = JsonConvert.DeserializeObject<JObject>(json);
foreach(JObject obj in result["d"])
{
Console.WriteLine(obj["Id"]);
}
Full example: dotNetFiddle

Categories

Resources