I am using C# to grab values from a JSON file and put them into a database. I am new to JSON and so don't really know too much of how to work with it. I will do my best to explain the structure I have and what I am trying to do. But to sum up I am trying to call a variable from JSON in a similar way you would do in an SQL Where statement. So grab this value where this other value = x.
So the JSON format is as follows.
Firstly it idenfitifies the columns.
"columns": [
{
"id": 8098453499733892,
"index": 0,
"title": "Task Name",
"type": "TEXT_NUMBER",
"format": ",,,,,,2,,,,,,,,,1",
"primary": true,
"width": 378
},
{
"id": 780104105256836,
"index": 1,
"title": "KPI (RYG)",
"type": "PICKLIST",
"symbol": "RYG",
"options": [
"Red",
"Yellow",
"Green"
],.....
Then the rows and cells within that:
"id": 2157159933863812,
"rowNumber": 2,
"parentRowNumber": 1,
"parentId": 7786659468076932,
"expanded": false,
"format": ",,1,,,,,,,22,,,,,,",
"createdAt": "2015-03-04T15:58:28+13:00",
"modifiedAt": "2015-03-04T15:58:32+13:00",
"cells": [
{
"columnId": 8098453499733892,
"type": "TEXT_NUMBER",
"value": "GLH Toll MASTER FROM WEEK 47",
"displayValue": "GLH Toll MASTER FROM WEEK 47",
"format": ",,1,,,,2,,,22,,,,,,1"
},
{
"columnId": 2750428942231428,
"type": "CHECKBOX",
"value": true,
"format": ",,1,,,,,,,22,,,,,,"
},
Ok so for an example. What I want to do is grab the columnID value in the cell, and then use that to find the title value in the column. So in the above example, I would want to find 'title' where id in column equals 8098453499733892, which would give me the result of 'Task Name'.
I don't even know if this is possible but have struggled to find a working example on the web. FYI I am using smartsheets.
You need to create an equivalent object/class in your c# containing those properties in your JSON. In order to get the columnID column based on your JSON structure, you need to create the the class below:
class Class1 {
public string id { get; set; }
public int rowNumber { get; set; }
public int parentId { get; set; }
public bool expanded { get; set; }
public string format{ get; set; }
public List <Cells> cells {get; set;}
}
class Cells {
public string columnId {get; set;}
public string type{get; set;}
public bool value{get; set;}
public string format {get; set;}
}
You need to deserialize the JSON string from the API using the Class1 object and from there you can access whatever column that you need.
For anyone looking I used the where clause in the select token. Here is the code that I used to find the column title based on an id value.
var test = jObject.SelectToken("columns").Where(t => t["id"].Value<Int64>() == 5283703732627332).FirstOrDefault()["title"].Value<string>();
Related
I need to inject the specific property value to object that is being deserialize using JsonConvert.DeserializeObject method.
for example I have a class
public class Employee
{
public int EmployeeID {get; set;}
public string Name {get; set;}
public int OrgnizationID {get; set;}
}
Json
[
{
"employeeID": 1,
"name": "Neeraj"
},
{
"employeeID": 2,
"name": "Sam"
},
{
"employeeID": 3,
"name": "Jonson"
}
]
above json string converting to list of employee. Here I am looking a way to set the OrgnizationID with some value for full of list. I know I can set it after conversion, but god to have if I can set it along with conversion.
var employees = JsonConvert.DeserializeObject<List<Employee>>(jsonData);
in above line of code I am also passing the JsonSerializerSettings for some other purpose that not defined here just to keep question simple.
I'm having problems when trying to save an object that has a dynamic property in RavenDB
The object I'm trying to save represents an order. The order contains a list of orderlines so imagine the following Order class:
public class Order {
public int Id { get; set; }
public List<Orderline> Orderlines { get; set; }
}
And the Orderline class being:
public class Orderline {
public Product Product { get; set; }
public int Quantity { get; set; }
public dynamic Attributes { get; set; }
}
The object I'm trying to save (I'll display it with JSON);
{
"Id": 0,
"Orderlines": [
{
"Product": {
"Id": 0,
"Name": "Some product"
},
"Quantity": 1,
"Attributes": {
"color": "Red"
}
}
]
}
Saving it does not throw any errors
RavenDB stores the Order object as
{
"Id": 0,
"Orderlines": [
{
"Product": {
"Id": 0,
"Name": "Some product"
},
"Quantity": 1,
"Attributes": {
"$type": "Newtonsoft.Json.Linq.JObject, Newtonsoft.Json",
"color": {
"$type": "Newtonsoft.Json.Linq.JValue, Newtonsoft.Json",
"$values": []
}
}
}
]
}
Note that the values property of Order.Orderlines[0].Attributes.color is not set...
When I try to serialize the object back to my C# Order object I get the following exception;
Unable to cast object of type
'Raven.Imports.Newtonsoft.Json.Utilities.CollectionWrapper`1[Newtonsoft.Json.Linq.JToken]'
to type 'Newtonsoft.Json.Linq.JValue'.
What am I doing wrong, how can I store this object in the RavenDB database and retrieve it?
What is the type that you are actually saving into attributes?
Typically you'll use something that is actually dynamic, like ExpandoObject
Storing the dynamic property with type 'dynamic' apparently wasn't enough. When I gave the Attributes property the ExpandoObject type, RavenDB stored the Attributes property as normal JSON (without $type and $values, so clean as desired)
When retrieving it back from the RavenDB database it deserializes back to an ExpandoObject object.
Make sure to cast the ExpandoObject property to a dynamic (e.g. 'as dynamic') when trying to display the property in a Razor view.
I'm using NJsonSchema v2.6 for generating the JSON Schema for the following class:
[DataContract(Name = "Message", Namespace = "")]
public class AMessageModel
{
[DataMember]
internal Guid MessageId { get; set; }
internal DateTime MessageDate { get; set; }
}
[DataContract(Name = "Message", Namespace = "")]
public class AddUserMessage : AMessageModel
{
[DataMember]
public string AccountName { get; set; }
[DataMember]
public string FistName { get; set; }
[Range(2, 5)]
[DataMember]
public string LastName { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public string Password { get; set; }
}
The generated JSON Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"typeName": "AddFitnessHubAccountMessage",
"additionalProperties": false,
"properties": {
"AccountName": {
"type": [
"null",
"string"
]
},
"FistName": {
"type": [
"null",
"string"
]
},
"LastName": {
"type": [
"null",
"string"
]
},
"Email": {
"type": [
"null",
"string"
]
},
"Password": {
"type": [
"null",
"string"
]
}
},
"allOf": [
{
"type": "object",
"typeName": "AMessageModel",
"additionalProperties": false,
"properties": {
"MessageId": {
"type": "string",
"format": "guid"
},
"MessageDate": {
"type": "string",
"format": "date-time"
}
}
}
]
}
Even though the MessageDate property is not marked as a DataMember, it is always included in the schema, also the generated schema includes two schema paths when it should only include one, it seems that the parser is not flattening the properties.
UPDATE
This fixes the issue with multiple schema paths being created
new JsonSchemaGeneratorSettings
{
FlattenInheritanceHierarchy = true
}
GitHub Issue: https://github.com/NJsonSchema/NJsonSchema/issues/53
I'm the author of the library NJsonSchema.
Ignored properties
There was a bug in the library and now (v2.7+) property ignore works as follows:
A property is ignored when either
The property is marked with the JsonIgnoreAttribute property
The class has an DataContractAttribute attribute and the property has no DataMemberAttribute and no JsonPropertyAttribute
https://github.com/NJsonSchema/NJsonSchema/wiki/JsonSchemaGenerator
Flatten inheritance hierarchy
As you already found out, you can flatten the inheritance hierarchy via the FlattenInheritanceHierarchy setting...
The library is mainly used for code generation, and thus the inheritance is usually needed.
Since NJsonSchema has a dependency on Newtonsoft.Json, have you tried this from the Newtonsoft.Json documentation?
Conditional Property Serialization
To conditionally serialize a property, add a method that returns
boolean with the same name as the property and then prefix the method
name with ShouldSerialize. The result of the method determines whether
the property is serialized. If the method returns true then the
property will be serialized, if it returns false then the property
will be skipped.
I have a standard Parent / Child EF model as below
public class DataDictionary
{
public int Id { get; set; }
public String Name { get; set; }
public int? ParentId { get; set; }
[JsonIgnore]
public virtual DataDictionary Parent { get; set; }
public virtual ICollection<DataDictionary> Children { get; set; }
}
I am exposing this as a REST api via WebApi and currently it will return the complete parent child hierarchy when I GET a node as below.
{
"Id": 1,
"Name": "root",
"SegmentKey": null,
"ParentId": null,
"Children": [{
"Id": 2,
"Name": "Demographics",
"SegmentKey": null,
"ParentId": 1,
"Children": [{
"Id": 3,
"Name": "Gender",
"ParentId": 2,
"Children": []
}, {
"Id": 4,
"Name": "Age",
"ParentId": 2,
"Children": []
}, {
"Id": 5,
"Name": "Income",
"ParentId": 2,
"Children": []
}]
}, {
"Id": 6,
"Name": "Activity",
"SegmentKey": null,
"ParentId": 1,
"Children": [{
"Id": 7,
"Name": "Navigation",
"SegmentKey": null,
"ParentId": 6,
"Children": []
}, {
"Id": 8,
"Name": "Behaviour",
"SegmentKey": null,
"ParentId": 6,
"Children": []
}]
}]
}
However I need to get the requested object and the immediate children only to be returned only so that my consumers can build up the visual representation as the user navigates through the data.
UPDATE: Thanks for the comments guys, all looks good taking off the virtual however am struggling with the .Include as I am in an async method where the find returns the object and I have lost the context. i.e.
[ResponseType(typeof(DataDictionary))]
public async Task<IHttpActionResult> GetDataDictionary(int id)
{
DataDictionary dataDictionary = await db.DataDictionaries.FindAsync(id);
if (dataDictionary == null)
{
return NotFound();
}
return Ok(dataDictionary);
}
Any help would be gratefully received
For you it happens because of "virtual" keyword that's used in your entity. This keyword enables lazy loading for your collection, so when serializer comes to serializing your children collection, it tries to enumerate this collection, causing it to be loaded from database. After that, each element in this collection is serialized recursively, causing load for each children collection load from the database (with N+1 select problem).
To do what you want you need to:
First, delete virtual keyword from your Children property:
public class DataDictionary
{
public int Id { get; set; }
public String Name { get; set; }
public int? ParentId { get; set; }
[JsonIgnore]
public virtual DataDictionary Parent { get; set; }
public ICollection<DataDictionary> Children { get; set; }
}
Second, you need to eagerly load this collection in your controller. This code will cause only 1 level to be loaded for your dataDictionary class instance:
[ResponseType(typeof(DataDictionary))]
public async Task<IHttpActionResult> GetDataDictionary(int id)
{
DataDictionary dataDictionary = await db.DataDictionaries
.Include(x=>x.Children)
.FirstOrDefaultAsync(x=>x.Id == id);
if (dataDictionary == null)
{
return NotFound();
}
return Ok(dataDictionary);
}
Don't forget adding using System.Data.Entity in the beginning of the file to have access to .Include() function.
Also, consider not using Entity Framework entities in your api - better create DTOs, that will allow you to have less dependancy on your DB structure by API - API will have only a subset of fields for EF entity. You will also be able to limit tree depth here, making a child class that does not have Children collection.
Hope this helps!
If you don't want that the hole Children list get retrieved, remove the virtual keyword.
And independently program a function to load the first Child.
I am trying to create a model that would match the JSON.NET deserealization of this JSON structure:
First item...
{
"190374": {
"vid": 190374,
"canonical-vid": 190374,
"portal-id": 62515,
"is-contact": true,
"profile-token": "AO_T-mN1n0Mbol1q9X9UeCtRwUE1G2GFUt0VVxCzpxUF1LJ8L3i75x9NmhIiS0K9UQkx19bShhlUwlIujY4pSXAFPEfDG-k9n8BkbftPw6Y5oM3eU5Dc_Mm-5YNJTXiWyeVSQJAN_-Xo",
"profile-url": "https://app.hubspot.com/contacts/62515/lists/public/contact/_AO_T-mN1n0Mbol1q9X9UeCtRwUE1G2GFUt0VVxCzpxUF1LJ8L3i75x9NmhIiS0K9UQkx19bShhlUwlIujY4pSXAFPEfDG-k9n8BkbftPw6Y5oM3eU5Dc_Mm-5YNJTXiWyeVSQJAN_-Xo/",
"properties": {
"phone": {
"value": "null"
},
"hs_social_linkedin_clicks": {
"value": "0"
},
"hs_social_num_broadcast_clicks": {
"value": "0"
},
"hs_social_facebook_clicks": {
"value": "0"
},
"state": {
"value": "MA"
},
"createdate": {
"value": "1380897795295"
},
"hs_analytics_revenue": {
"value": "0.0"
},
"lastname": {
"value": "Mott"
},
"company": {
"value": "HubSpot"
}
},
"form-submissions": [],
"identity-profiles": []
},
"form-submissions": [],
"identity-profiles": []
},
**next similar entry**
Then I try to bind with List of this:
public class HubSpotEmailRqst
{
public int vid { get; set; }
public int canonical-vid { get; set; }
public int portal-id { get; set; }
public bool is-contact { get; set; }
public String profile-token { get; set; }
public String profile-url { get; set; }
public Dictionary<string, string> properties { get; set; }
public Dictionary<string,string> form-submissions { get; set; }
public Dictionary<string,string> identity-profiles { get; set; }
}
I am not sure this will bind either, but I cannot get past the fact we cannot have hyphen in the field names, how can I get around this?
There're two ways to use properties with hyphens:
Name properties according to C# rules, but decorate them with [JsonProperty("property-name")] attribute.
Use custom contract resolver which modifies property names. For example, if all properties in JSON are named consistently, you can use regex to change PascalCase C# property names to lower-case JSON property names. See CamelCasePropertyNamesContractResolver from Json.NET for example implementation.
If I'm understanding the question correctly, you are upset that you can't use a hyphen in a field name in a C# program? Why not use CamelCase to identify the fields? Instead of is-contact use 'isContact'. Instead of canonical-vid. use canonicalVid. Sure, the names may look different, but to the programmer the meaning should be clear.