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.
Related
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?
I present a simple model:
public class UserDocument
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string DisplayName { get; set; }
public List<string> Friends { get; set; }
}
I am using the latest C# driver which has the ability to replace a document using a C# object which will automatically update all its fields. Problem is I want to update all fields except for the user friends, because it's a field containing the object relations to other documents. Of course I can manually update each field of the ones I want to get updated, which here are just two.
But this example is simple just to make my point. In reality the fields are much more and it would be harder to update each field. That would require a single line for each one to use the Set operator. Also, newly-added fields would have to be supported in the same way as opposed to updating to automatically just works.
Is there a way to achieve that - automatically update all fields with just specifying a list of excluded fields?
There is no way, using the provided builders to have a "blacklist" update which excludes only specific fields.
You can query the old document, copy the old values of these fields to the new instance and then replace it entirely in the database.
You can also generate such an update command by iterating over the fields using reflection.
But the MongoDB driver doesn't offer such a query built in.
I figured out a way to do this with MongoDB using Javascript/NodeJS, but maybe the logic can translate to C#?
I wanted to update all fields without having to actually explicitly state them (all fields except for one, it turned out).
Attempted update of all document fields:
await examCollection.findOneAndUpdate(
{_id: new ObjectID(this.examId)},
{$set: this.data}
)
...except, this.data happened to have _id in it as well, which I didn't want to update. (In fact, it gave me an error, because _id is immutable.)
So, for my workaround, I ended up "deleting" all fields on the object that I didn't want to update (i.e. _id).
Successful update of all non-specified document fields:
// (1) specify fields that I don't want updated (aka get rid of them from object) (similar option in C#?)
delete this.data._id
//delete this.data.anotherField
//delete this.data.anotherField2
//delete this.data.anotherField3
// (2) update MongoDB document
await examCollection.findOneAndUpdate(
{_id: new ObjectID(this.examId)},
{$set: this.data}
)
This was much easier than explicitly stating all the fields I did want to update, because there were A LOT, and they could potentially change in the future (new fields added, fields deleted, etc.).
Hopefully this strategy can help!
Note: In reality, I did my "field specifying" earlier in another file, rather than immediately before updating like it shows in the example, but same effect.
There must be a program that should generate WORD document (but that's not the point). It generates a document by data that the user writes in the program. And sometimes there is need to close application and do some other work and user don't want to lose all progress. And here we must keep all the "changes" that user have entered. Previously, I have saved all .ini file (under the instruction http://www.codeproject.com/Articles/1966/An-INI-file-handling-class-using-C) it was enough for me for test, but in real cases ini was not enough, because if I save the textbox with multiline so record to inin file goes wrong, and when reading ini file - readed was only the first line and then only the first 255 characters.
Here is an example of what should be saved:
information about all checked checkboxes radiobuttons etc. (in
INI-expample I show it in CHECKOUTS and COMPARING sections)
the data from all textboxes on the main form (MAIN section)
most importantly, objects of 'implementation' and 'screens' class.
Now about class 'implementation': Each implementation may have a name, description, status, and a list of links to screenshots. To do this, I created a listbox with list of screenshots for each implementation (ScreenList) and a separate listbox for all implementations. Ie when I fill the data I store object in listbox, and then if I need I can just get access to it. And when I save a list of all implementations into ini I first of all write the number of all implementations to be able get access in loops (for, while etc) to each object (all in INI and CODE examples: Section IMPLEMENTATIONS, IMPLEMENTATION_n ...)
And the question is: how to save these Data? As I know Microsoft has abandoned ini and use the xml, but I can't google it correctly. Someone suggested I use serialization of data in xml, but as far as I could google - Serialization is used only for one object of class, and I have a lot of these objects are, othervide I still have and values of all the checkboxes and more. Ie I need to save all the values of controls , all the objects of classes implement and screen, and then read these values and write them right back to where they were taken . How to do that?
Code examples:
//........save object to listbox
Implement imp = new Implement(impName.Text, impDescr.Text, impStatus.Text, ScreenList);
listBox1.Items.Add(imp);
//......
//in implement class, Screens is list of screenshots that is get from another listbox
private List<string> _Screens = new List<string>();
public Implement(string Name, string Description, string Status, ListBox Screen)
{
_Name = Name;
_Description = Description;
_Status = Status;
for(int i=0;i<Screen.Items.Count;i++)
{
_Screens.Add(Screen.Items[i].ToString());
}
}
//....getting access to implementation
Implement imp = (Implement)listBox1.SelectedItem;
....
Ini example:
[MAIN]
Languages=Polish
Comment=Comment lalarar larl alrlalrl
Status=Correct
[CHECKOUTS]
Enable=True
SLDoc=False
SLDocTab=True
SaveDoc=True
LoadDoc=False
SendDoc=False
Correctly=True
CorrNum=50
[COMPARING]
Enable=True
NoDif=False
Declar=True
UnDecl=False
UnDeclDESCR=
[IMPLEMENTATIONS]
COUNT=2
[IMPLEMENTATION_0]
Name=Implement 1 CORRECT
Descr=text text test text
Status=Correct
ScreenCount=2
Screen_0=C:\1.png
Screen_1=C:\2.png
[IMPLEMENTATION_1]
Name=IMPLEMENT 2 INCORRECT
Descr=lala
Status=Incorrect
ScreenCount=2
Screen_0=C:\2.png
Screen_1=C:\3.jpg
[SCREENS]
COUNT=2
[SCREEN_0]
Descr=Screen 1
Screen=C:\1.png
[SCREEN_1]
Descr=Screen 2
Screen=C:\1.png
If I understood you correctly you should take a look at settings mechanism in c#.
I hope that this chapter of MSDN will be useful.
What you have to do is create some kind of Settings object. This should be a class that either has a specific property (or class for nested values) for each setting you like (e.g. public string Language {get; set; }) or you take a more generic way by using two dictionaries Dictionary<string, string> (for simple values), Dictionary<string, Settings> (a recursive structure for complex types).
Then your form should be able to create such a settings object an fill it with the desired data it needs to recreate the current state and it should be able to take such a settings object and change its current state to this settings object by setting all inner variable to the values within this object.
The next step would be to make this object serializable by either using XML serialization or Data Contract or whatever you like. Then you can write/load this object to/from disk and afterwards push it into the class that needs this state.
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?
I have a class I am using for serializing various configuration options for an application I am working on. I'm adding a new property to the class that is a List, and I'd like it to fill this list if it does not exist already in a XML file. My first thought was to check if the list contained zero items, however this is not acceptable because there are times I want to have zero items in the list. In essence I want a file that has been serialized with an older version of the same class to be "upgraded" and have defaults automatically inserted for new properties. How can I do this? For a more visual example of what I'm trying to do, see below:
When I deserialize an XML file that contains:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
and after I've added a list property it will serialze as:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
<Item3/>
I want it to serialize as:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
<Item3>
<DefaultSubItem/ Field="wtfe">
<DefaultSubItem/ Field="wtfe">
</Item3>
But allow me to change it to:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
<Item3></Item3>
Another option may be to use these attributes:
[OnSerializing()]
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.onserializingattribute.aspx
[OnDeserializing()]
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializingattribute.aspx
I think your looking for the SerializationBinder class:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder%28VS.71%29.aspx