I have a service call that accepts the following model:
public class ServiceModel {
public DataModel dModel {get; set;}
public JObject schema {get; set;}
}
The DataModel is responsible for holding data that will be used to populate user defined schema (see below).
The schema is a user defined (at runtime) dynamic json structure that contains tokenized values like this. Being that it's user defined, it can be deeply nested.
{
"id": "<tokenized_id>",
"hero":{
"heroName": "<tokenized_heroName>",
"heroType": "<tokenized_heroType>",
"heroSkill": "<tokenized_heroSkill>",
"heroArmor": {
"armor_id": "<tokenized_armorId>",
...
}
}
}
What I want to do is pull data from the DataModel and replace the corresponding tokenized value with it. The tricky part comes from the possibility of deeply nested objects
My first idea is to just flatten the schema into a string and doing a Find/Replace on the entire string but I'm curious if there's a more elegant way.
There's the option of working with JObjects or even Dictionary but neither provide a nice way to access nested objects. I believe I would need to use recursion which could get ugly.
Are there betters ways to accomplish this?
Related
I need to store a standard record structure in a template file that can be loaded in by a c# program. The record structure relates to a new entry in a database.
Each new entry has:
- a header which has a list of values for that table, and
- a list of items that link to the new entry
Now, here's the tricky part.
- Each item can itself have a list of sub-items (that are all item type)
The program should load in the template, create a new record, and then process each item one at a time. If the item contains a list of sub-items, those will be processed before the parent item is completed.
I was thinking I could perhaps achieve this using JSON?
I will not give you code for doing this but may be enough pointers.
Design the Class that should represent your Record. Ex:
If my record is that of an Employee
public class Employee
{
public string Name {get; set;}
public string EmpId {get; set;}
public Link<Jobs> JobHistory {get; set;}
}
Read about Serializers. Using them you can convert objects to Binary, Xml, Json etc. formats. So this is key for getting the state/stuff that needs to be persisted.
Read about File handling stuff in System.IO. File.Write/Read methods. Also, how to use these along with Serializers (may need to read on MemoryStream/StreamReader/Writers etc). This will help you write the persistable state into file system.
Thanks Prateek Shrivastava,
Lists was the solution I was looking for.
I tried storing the data as JSON, but worked out better to create a few additional tables in the database, and write an app to create and edit templates.
Using JSON.NET for the serialisation and deserialisation.
First of all; I'm using Newtonsoft.Json to deserialize JSON into objects like this:
JSON:
[{"number":22041}]
Order Object
[JsonProperty("number")]
public string OrderNumber { get; set; }
However, depending on which version the 'other' side is on, the Json may change into
[{"order_number":22041}]
So I'd actually like to pre-define "number" and "order_number" to both deserialize into my OrderNumber.
Is there a way to achieve something like the following (that actually works)
[JsonProperty("order_number")]
[JsonProperty("number")]
public string OrderNumber { get; set; }
I could write another class that has the same properties but with other JsonProperties depending on the Version they are on, but that seems like something to try last, unless there is no possible way to do this easier.
Update
I agree that this question is a duplicate of the question above. However since the given keys in the JSON changes significantly, I will be making duplicate objects (OrderV1 , OrderV2 as example).
Simply replacing some characters into other ones will not be enough in my case.
Let's say I have some json similar to the following:
"productdetails": [["loading"], ["loaded"], ["detailkey", "detailvalue"]]
The formatting is out of my control, and I need to be able to access the 'loading' and 'loaded' parts to make sure the data was loaded properly before moving on further to continue work with the data. I haven't been able to figure out how to setup nested properties that also have no key.
Edit: Should have noted, 'loading' and 'loaded' can be different things and there can be varying amounts of status update arrays before the details or other messages. So, the above could be returned, or something like this:
"productdetails": [["loading"],["empty"],["created"],["loaded"],["detailkey", "detailvalue"]]
Edit 2: Excuse the errors in my json syntax, the colons have been switched out to create a properly syntaxed example.
This is just a two-dimensional array, which can be represented as a list of list of string
You should be able to deserialize it to this object:
public class RootObject
{
public List<List<string>> productdetails { get; set; }
}
I recomment Newtonsoft's Json.Net parser.
Example:
string jsonString = "{\"productdetails\": [[\"loading\"], [\"loaded\"], [\"detailkey\", \"detailvalue\"]]}";
RootObject obj = JsonConvert.Deserialize<RootObject>(jsonString);
I use an API which returns JSON. I'm having trouble with accessing elements when they are not in an array.
My JSON looks like this:
On the JSON of 2, I can access the elements with
dataJson.Storingen.Ongepland.Storing.#elementName#
However, when I use the JSON of 1, I get the following exception:
Additional information: Newtonsoft.Json.Linq.JProperty does not contain a definition for Traject
The structure of second json is different about the first.
In second case, you should use dataJson.Storingen.Ongepland.Storing[0].#property to access the property that you want.
But if you want to roll up in your array, just to use a for
The two JSONs on that picture are not similar in architecture. The first one has a nested "Storing" object, that has several properties, but in the second case, "Storing" became an array of objects. Is it possible that your object model that you're trying to map to tries to parse this array as a single object?
If so, then I think you need to change the type of "Storing" in your model to an array. You will be able to get the elements then like this:
dataJson.Storingen.Ongepland.Storing[0].#elementName#
I know this is an old post, but I thought maybe I could just share my thoughts on this question number 1 I believe, just in case someone from the future saw this.
1st. Create two classes as such:
public Storing Test {get; set;}
public class Storing
{
public string id {set; get;}
public string Traject {set; get;}
public string Periode {set; get;}
}
2nd. In the main program, deserialize the JSON and call the object as such
TestCase list = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<TestCase>(*your web API uri*);
Console.WriteLine ("id:{0}, Traject{1}, Periode{2}", list.Id, list.Traject, list.Periode);
I'm researching MongoDB at the moment. It's my understanding that the official C# driver can perform serialization and deserialization of POCOs. What I haven't found information on yet is how a reference between two objects is serialized. [I'm talking about something that would be represented as two seperate documents, with ID links, rather than embeded documents.
Can the serialization mechanism handle this kind of situation? (1):
class Thing {
Guid Id {get; set;}
string Name {get; set;}
Thing RelatedThing {get; set;}
}
Or do we have to sacrifice some OOP, and do something like this? (2) :
class Thing {
Guid Id {get; set;}
string Name {get; set;}
Guid RelatedThing_ID {get; set;}
}
UPDATE:
Just a couple of related questions then...
a) If the serializer is able to handle situation (1). What is an example of how to do this without using embedding?
b) If using embedding, would it be possible to query across all 'Things' regardless of whether they were 'parents' or embedded elements? How would such a query look like?
The C# driver can handle serializing the class containing a reference to another instance of itself (1). However:
As you surmised, it will use embedding to represent this
There must be no circular paths in the object graph or a stack overflow will occur
If you want to store it as separate documents you will have to use your second class (2) and do multiple inserts.
Querying across multiple levels is not really possible when the object is stored as one large document with nested embedding. You might want to look at some alternatives like:
https://docs.mongodb.com/manual/applications/data-models-tree-structures/
Yes, That is completely possible.
One thing you must understand about MongoDB and most NoSQL solutions is that objects can be contained within other objects. In the case of MongoDB, it's basically, if you can create the object in JSON, then you can create the object in MongoDB.
In general, you should strive to have a "relatively" denormalized database structure. A little bit of duplicated data is ok as long as you're not updating it often.
If you really want a reference to another document, you can use a DBRef. However there is limitation with references in MongoDB.
you can only query by id on a ref
when you get your Thing's document, you'll have to make a second query to get the associated RelatingThing's document as join doesn't exists in MongoDB.
I've encountered the same issue recently, and I usually steer away from them but... I'm thinking that this could be a good use for a significant numbering system deployed on the Id field.
class Thing {
string Id {get; set;}
string Name {get; set;}
string RelatedThing {get; set;}}
So, simplifying, if Id was something like "T00001" (or indeed T + GUID), you could easily get the set of things from Mongo by querying for something like Id starts with T, and setting up objects for them all (or just for the subset you know contains your reference, if it is a very large set).
You know/expect that RelatedThing to be a Thing, but it will just be a string when it comes back from Mongo. But if you've set up objects as above, you could effectively use the string as if it were an object reference (after all, that is what it really is, done kind of "manually").
Its a 'loose' way of doing it, but might be workable for you.
Can anyone see any pitfalls with that approach?