JSON string array into Entity Framework - json

I'm trying to get a JSON file into a SQL Server database with auto identity keys and the correct foreign key relation. Everything is working gloriously with the exception of a string array. The data looks more or less like this:
{
"id" : "123",
"name" : "Some Stuff",
"phrase" : "More Stuff",
"type" : "ABC",
"label" : "Some label",
"responseType" : "The Response Type",
"answers" : [ "9" ]
}
The "answers" part is causing me fits. It looks like it's almost exclusively a single value, but it could potentially have multiple values like
"answers" : [ "6", "7", "8" ]
Now I know that a List is not supported in EF for native types like string or int. I ultimately would rather have a separate table for the list of answer values anyway, which I'm calling DataAnswers.
public partial class Response
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ResponseId { get; set; }
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
[JsonProperty("phrase", NullValueHandling = NullValueHandling.Ignore)]
public string Phrase { get; set; }
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
public string Type { get; set; }
[JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)]
public string Label { get; set; }
[JsonProperty("responseType", NullValueHandling = NullValueHandling.Ignore)]
public string ResponseType { get; set; }
[JsonProperty("answers", NullValueHandling = NullValueHandling.Ignore)]
public virtual List<DataAnswer> DataAnswers { get; set; }
}
public partial class DataAnswer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DataAnswerId { get; set; }
public string AnswerText { get; set; }
}
Currently here's the error I'm getting.
Newtonsoft.Json.JsonSerializationException: 'Error converting value
"9" to type 'ForeseeDemo.Data.DataAnswer'. Path
'items[0].responses[0].answers[0]', line 60, position 23.'
Any great ideas of how to get a list of answer strings into a table with a foreign key to the Response ?
Thanks in advance!

You could create a data transfer object then handle the conversion b/t that and the entity object.
You could create a custom JSON converter to handle conversion of the property.
You could create an additional property that is used for serialization/deserialization but not by EF and handle conversions there:
[JsonIgnore]
public virtual List<DataAnswer> DataAnswers { get; set; }
[NotMapped]
[JsonProperty( "answers", NullValueHandling = NullValueHandling.Ignore )]
public List<string> DataAnswerStrings
{
get => DataAnswers?.Select( da => da.AnswerText )?.ToList();
set => DataAnswers = value
?.Select( s => new DataAnswer() { AnswerText = s } )
?.ToList()
?? new List<DataAnswer>();
}

Related

Deserializing a Json array of objects in xamarin forms not working

I have a json api response of something like this:
[
{
"id": 1,
"accountnumber": "001303000023",
"accounttitle": "MEGA CROWN ",
"accountdesc": "MEGA CROWN ",
"productType": "Loan",
"prodname": "SME TERM LOAN ",
"bookbalance": -200000.00,
"effectivebalance": -200000.000000,
"currentbalance": -200000.0000
},
{
"id": 2,
"accountnumber": "1020145429",
"accounttitle": "MEGA CROWN",
"accountdesc": "CORPORATE ",
"productType": "Current",
"prodname": "CORPORATE CURRENT ACCOUNT ",
"bookbalance": 3000.00,
"effectivebalance": 23000.000000,
"currentbalance": 3000.0000
}
]
and here is my model class...
public class Balance
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("productType")]
public string AccountType { get; set; }
[JsonProperty("accountnumber")]
public string AccountNumber { get; set; }
public string accounttitle { get; set; }
public string accountdesc { get; set; }
public string prodname { get; set; }
public double effectivebalance { get; set; }
public double currentbalance { get; set; }
[JsonProperty("currentbalance")]
public double balance { get; set; }
public string AccountBalance { get; set; }
//public string AccountBalance
//{
// get
// {
// string bal = this.balance.ToString();
// var newBal = Math.Round(Convert.ToDouble(bal), 2).ToString("C", System.Globalization.CultureInfo.GetCultureInfo("en-us")).Replace("$", "N");
// return newBal;
// }
// set
// {
// AccountBalance = value;
// }
//}
public ImageSource WalletImage
{
get
{
var img = ImageAsset.WalletImage;
return img;
}
set
{
WalletImage = value;
}
}
public Transaction transactions { get; set; }
}
I have tried different approaches to deserialize but all is futile.
first method I tried is this:
List<Balance> userAccts = JsonConvert.DeserializeObject<List<Balance>>(jsonee);
But nothing seem to work. whenever I put a breakpoint on the above deserializer method, the call gets to the point of deserialization but doesn't go beyond that. It's always returning to the previous call then overtime will break the house.
Please any help will be deeply appreciated.
Note: I have even tried to add "{}" into the response using stringFormatter so as to be able to deserialize into a list but all proof futile.
I also tried to serialize the response then deserialize it again.
Wrap deserialise method into try catch and check what error you get exactly.
You have added "currentbalance" twice. One as property and other one as JsonPropertyAttribute with same name. Please keep only one.
public double currentbalance { get; set; }
[JsonProperty("currentbalance")]
public double balance { get; set; }
A member with the name 'currentbalance' already exists on
'StackQA_Console1.Balance'. Use the JsonPropertyAttribute to specify
another name.
Same code works for me after keeping single "currentbalance" property.

Get RAW Json with .NET Core Text.Json

I have pretty much the same question as this one:
Get Raw json string in Newtonsoft.Json Library
but now using the Text.Json.Serialization in .NET Core 3.1, I struggle to find the equivalent of JRaw.
I want to have an extensible object like:
{
"id": "myId",
"name": "name",
"description": "my description",
"extensions": {
"unit": "C°",
"minVal": "0",
"maxVal": "100",
"precision": "1",
"enum": ["str1", "str2"],
...
}
}
I want to get the Id, Name and Description set in an object, but the extensions is a bunch of properties which can be whatever. So I want to keep the RAW Json for this extensions.
public class MyData
{
public string id { get; set; }
public string name { get; set; }
public string description { get; set; }
[JsonConverter(typeof(RawJsonStringConverter))]
public string extensions { get; set; }
}
I am fighting with a custom converter as documented here:
https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to
I tried with string, JsonElement, object.
No success so far.
Any idea?
Using JsonElement seems to be enough, without any custom converter:
public class MyData
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public JsonElement? Extensions { get; set; }
}
edit: JsonElement? as nullable is better: it allows JsonElement to be fully optional, if you have the corresponding settings in JsonSerializerOptions.
I am working with the following JsonSerializerOptions:
public static JsonSerializerOptions UpdateJsonSerializerOptions(this JsonSerializerOptions options, bool enumAsString = true)
{
if (options == null)
options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.IgnoreNullValues = true;
options.WriteIndented = true;
if (enumAsString)
{
// convert enums as strings
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
}
return options;
}
IgnoreNullValues is the important part to have the proper conversion when no extensions at all in the input.
And CamelCase allows to stay with .NET property names (e.g 'Name') while the JSON will be with 'name'

Child of entity type is null while posting to Web Api

I am trying to post Json to web api
{
"Name" :"Irfan",
"Roles":[
{"RoleID" : 1}
,
{"RoleID" : 2}]
}
In web api i have model like this
public class Role
{
public Int32 ID { get; set; }
public Int32? RoleID { get; set; }
public Int32? UserID { get; set; }
}
public class User
{
public string Name { get; set; }
public List<Role> Roles { get; set; }
}
i am getting "Name" value but "Roles" is null. How can i get "Roles"?
Please refer to below code sample which works when testing :
[Route("test")]
public ActionResult<IEnumerable<string>> test(User user)
{
return new string[] { "value1", "value2" };
}
The request will like :
POST https://localhost:XXXX/api/values/test
Content-Type: application/json
{"Name" :"Irfan","Roles":[{"RoleID" : 1},{"RoleID" : 2}]}
Checking your request using Fiddler/Postman , .NET Core will help automatically mapping json to object on server side .
Create object of roles in constructor
public class User
{
public User()
{
this.Roles = new List<Role>();
}
public string Name { get; set; }
public List<Role> Roles { get; set; }
}

How to Deserialize Complex JSON file in SSIS into few columns

I have a JSON file that is pretty complex. Here is a snippet of my file:
JSON
"SKU": "12345",
"Status": {
"Health": "OK"
},
"Type": "ComputerSystem",
"Name": "Cartridge 1",
"Power": "Off",
"AssetTag": "12345",
"HostCorrelation": {
"IPAddress": [],
"HostMACAddress": [
"00:00:00:00:00:00",
"11:11:11:11:11:11"
]
},
"SerialNumber": "12345",
"Boot": {
"BootSourceOverrideSupported": [
"None",
"PXE",
"HDD",
"iSCSI",
"M.2",
"None"
],
"BootSourceOverrideTarget": "PXE",
"BootSourceOverrideEnabled": "Continuous"
}
Without showing all the classes here is the RootObject VS generates as code:
Paste JSON as Class
public class Rootobject
{
public string SKU { get; set; }
public Status Status { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public string Power { get; set; }
public string AssetTag { get; set; }
public Hostcorrelation HostCorrelation { get; set; }
public string SerialNumber { get; set; }
public Boot Boot { get; set; }
public Links links { get; set; }
public string UUID { get; set; }
public Bios Bios { get; set; }
public Oem Oem { get; set; }
public Memory Memory { get; set; }
public Availableaction[] AvailableActions { get; set; }
public string SystemType { get; set; }
public Processors Processors { get; set; }
public string Model { get; set; }
public string Manufacturer { get; set; }
}
I want to loop through multiple JSON files with this structure, and put them into a few columns such as (Section, Component, Property, and Value).
However, I have been having a hard time figuring this out. It would be simple to put each part into its own unique column.
The end result of my JSON example above may look like:
Goal SQL Output
The format doesn't have to be exact, but something along those lines. If there is a better way of doing this I am all ears.
I can tell you didn't post all of your classes because the RootObject has object references, but this is how you could start your code. This won;t get your data into the format you asked for, but it is how the serializer works.
string json = [Somehow get your json in to a string]
JavaScriptSerializer js = new JavaScriptSerializer();
var jRow = js.Deserialize<Rootobject>(json);
// now you have your entire JSON in one object.
//for the data you presented you will need a few outputs:
// let's start with the outermost:
Output0Buffer.AddRow();
Output0Buffer.SKU = jRow.SKU;
Output0Buffer.Health = jRow.Status.Health; //There is only one option here
Output0Buffer.Type = jRow.Type ;
Output0Buffer.Name = jRow.Name;
Output0Buffer.Power = jRow.Power ;
Output0Buffer.AssetTag = jRow.AssetTag ;
Output0Buffer.SerialNumber = jRow.SerialNumber ;
Output0Buffer.BootSourceOverrideTarget= jRow.Boot.BootSourceOverrideTarget ;
Output0Buffer.BootSourceOverrideEnabled= jRow.Boot.BootSourceOverrideEnabled;
//this is a new output of boot details linked by SKU
foreach(var dtl in jRow.Boot.BootSourceOverrideSupported)
{
OutputBootStuffBuffer.AddRow();
OutputBootStuffBuffer.SKU = JRow.SKU; //Making assumption that SKU is the key back
OutputBootStuffBuffer.BootSourceOverrideSupported = dtl.BootSourceOverrideSupported;
}

Deserialize OneNote JSon result

I'm trying to deserialize some OneNote API results. Below is my:
Example result from notebook query
Sample Class
Code to deserialize (two attempts obj1 and obj2
Content-Type: application/json
X-CorrelationId: <GUID>
Status: 200 OK
{
"#odata.context":"https://www.onenote.com/api/v1.0/$metadata#notebooks","value":[
{
"isDefault":false,
"userRole":"Contributor",
"isShared":true,
"sectionsUrl":"https://www.onenote.com/api/v1.0/notebooks/notebook ID/sections",
"sectionGroupsUrl":"https://www.onenote.com/api/v1.0/notebooks/notebook ID/sectionGroups",
"links":{
"oneNoteClientUrl":{
"href":"https:{client URL}"
},"oneNoteWebUrl":{
"href":"https://{web URL}"
}
},
"id":"notebook ID",
"name":"notebook name",
"self":"https://www.onenote.com/api/v1.0/notebooks/notebook ID",
"createdBy":"user name",
"lastModifiedBy":"user name",
"createdTime":"2013-10-05T10:57:00.683Z",
"lastModifiedTime":"2014-01-28T18:49:00.47Z"
},{
"isDefault":true,
"userRole":"Owner",
"isShared":false,
"sectionsUrl":"https://www.onenote.com/api/v1.0/notebooks/notebook ID/sections",
"sectionGroupsUrl":"https://www.onenote.com/api/v1.0/notebooks/notebook ID/sectionGroups",
"links":{
"oneNoteClientUrl":{
"href":"https://{client URL}"
},"oneNoteWebUrl":{
"href":"https://{web URL}"
}
},
"id":"notebook ID",
"name":"notebook name",
"self":"https://www.onenote.com/api/v1.0/notebooks/notebook ID",
"createdBy":"user name",
"lastModifiedBy":"user name",
"createdTime":"2011-07-20T03:54:46.283Z",
"lastModifiedTime":"2014-06-24T20:49:42.227Z"
}
]
}
[DataContract]
public class Notebooks
{
[DataMember]
public bool isDefault { get; set; }
[DataMember]
public string userRole { get; set; }
[DataMember]
public string isShared { get; set; }
[DataMember]
public string sectionsUrl { get; set; }
[DataMember]
public string sectionGroupsUrl { get; set; }
[DataMember]
public string oneNoteWebUrl { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string self { get; set; }
[DataMember]
public string createdBy { get; set; }
[DataMember]
public string lastModifiedBy { get; set; }
[DataMember]
public string lastModifiedTime { get; set; }
[DataMember]
public string id { get; set; }
[DataMember]
public string createdTime { get; set; }
}
// This sample web string returned from the Web Request is stored in this textbox
string resultStr = resultTextBox.Text.ToString();
var obj1 = DeserializeJSon<List<Notebooks>>(resultStr);
foreach (Notebooks nb in obj1)
{
string id = nb.ToString();
}
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<Notebooks>));
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(resultStr));
var obj2 = (List<Notebooks>)ser.ReadObject(stream);
foreach (Notebooks nb in obj2)
{
string id = nb.id.ToString();
}
public static T DeserializeJSon<T>(string jsonString)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
T obj = (T)ser.ReadObject(stream);
return obj;
}
You are not being able to deserialize the result because the JSON returned by the OneNote API is not a List of Notebook objects. It is one main object with two properties: "#odata.context" and "value". "value" itself is a list of Notebook objects.
I suggest you make a class like the following
public class OneNoteJsonResponse
{
[DataMember(Name = "#odata.context")]
public string ODataContext {get; set;}
[DataMember]
public List<Notebook> value {get; set;}
}
Then try deserializing the response using DataContractSerializer following this example:
Deserialize JSON with C#
I personally would recommend using JSON.NET instead of the DataContractSerializer, as it provides more flexibility and better performance. You can install it easily using nuget.
http://james.newtonking.com/json
Let us know if you have any issues, happy coding!
EDIT: Also, the Notebook object you have is missing the "links" object, which would be another class of its own. (containing the oneNoteClientUrl and OneNoteWebUrl)
response string cannot be used verbatim with your data model. start from "value".
alternatively, have a look at http://json2csharp.com/
hth