For example:
json:
{
"ObjectA": {
"id": 1,
"name": "steve",
"hobbies": 1
},
"ObjectB": {
"id": 2,
"name": "dave",
"age": 55
}
}
c# class:
public class ObjectA
{
public int id { get; set; }
public string name { get; set; }
public int hobbies { get; set; }
}
public class ObjectB
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
}
public class Root
{
public ObjectA ObjectA { get; set; }
public ObjectB ObjectB { get; set; }
}
Now I guess that the ObjectA and ObjectB could inherit from a base class giving:
public class ObjectBase
{
public int id { get; set; }
public string name { get; set; }
}
public class ObjectA : ObjectBase
{
public int hobbies { get; set; }
}
public class ObjectB : ObjectBase
{
public int age { get; set; }
}
public class Root
{
public ObjectA ObjectA { get; set; }
public ObjectB ObjectB { get; set; }
}
Now I could create a object from the json using:
Root object = JsonConvert.DeserializeObject<Root>(json);
My question is, for a given id, how could I find the corresponding name or i guess even more useful and as a precursor to name - the corresponding property of object
In practice there would be many objects, so to manually check object.ObjectA.id etc. would be impractical.
CodePudding user response:
Name only lookup
If you need to look up the name property based on the id then you can do that with the following code:
var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var name = (from node in semiParsed.Values
let id = (int)node.GetValue("id")
where id == lookupId
select (string)node.GetValue("name"))
.FirstOrDefault();
Console.WriteLine(name);
- First we deserialize the json into a collection
- The top most properties' name will be the keys of the
Dictionary - The top most properties' object will be treated as
JObjects (semi parsed jsons)
- The top most properties' name will be the keys of the
- Then we perform a Linq to Json query
- We iterate through the
JObjects and retrieve theiridpropertyGetValuereturns aJTokenand since we know it is a number, we cast it toint
- We perform a filtering based on the
lookupId - And we select the
nameproperty's value
- We iterate through the
- Finally we need to issue a
FirstOrDefaultmethod call because the previous query returns anIEnumerable<string>
Here I have assumed that the the id is unique. If the provided lookupId is not defined inside the json then the result will be null.
Wrapping object lookup
If you need to perform a look up for the wrapping object then you need to use Json.NET Schema as well:
var generator = new JSchemaGenerator();
JSchema schemaA = generator.Generate(typeof(ObjectA));
JSchema schemaB = generator.Generate(typeof(ObjectB));
var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var theNode = (from node in semiParsed.Values
let id = (int)node.GetValue("id")
where id == lookupId
select node)
.FirstOrDefault();
if (theNode == null)
return;
if (theNode.IsValid(schemaA))
{
var objA = theNode.ToObject<ObjectA>();
Console.WriteLine(objA.hobbies);
} else if (theNode.IsValid(schemaB))
{
var objB = theNode.ToObject<ObjectB>();
Console.WriteLine(objB.age);
}
- First we generate two json schemas from the class definitions
- Then we perform almost the same query the only difference here is the
selectpart- We return here the whole
JObjectobject instead of just its name
- We return here the whole
- Finally perform a schema validation
- If the retrieved json matches to
schemaAthen we can safely convert (ToObject) toObjectA - We check the json against
schemaBas well
- If the retrieved json matches to
CodePudding user response:
the simpliest way would be convert your json to dictionary of JObjects
var dict = JObject.Parse(json).Properties().ToDictionary(jo => jo.Value["id"],jo=>jo.Value);
var searchId=2;
var name = dict[searchId]["name"]; // dave
