I recieve a JSON file from database in the c# client. Then I deserialize this JSON to an object of a class. Now when updated JSON arrives from database afterwards, what I want is to somehow replace every data of the old object with a new one. I need this because rest of code has many references to the old object and its properties, so simply assigning new object to old one would not work as all references would be lost. Is the only solution here performing a deep copy of the object? If so what is a best way to do this? Honestly I never needed anything like that for many years, I am quite surprised that this issue arise now but the reason is probably that I recieve dataj from database in JSON and have to someho deserialize it into new object.
The only solution I tried is manual copying of the fields betwee new and old object but its a pain to keep it updated whenever I change the class structure which I do a lot
SUGGESTION: Create a wrapper class with a property for the actual data. Pass a reference to your wrapper; read or update the data at will. The "reference" is unchanged; everybody will automatically "see" any data updates.
public class MyWrapper
{
public MyDataClass MyData { get; set; }
}
public class SomeClass
{
public void SomeMethod ()
{
// Instantiate your data
var wrapper = new MyWrapper();
wrapper.MyData = ReadFromDbAndDeserialize();
// And pass it to other client(s)
SomeOtherMethod(wrapper);
}
}
You could use Automapper to create deep copies automatically. You would need to set up some mappings manually though but it's less painful anyway.
Related
I find myself a bit lost on this one. I honestly can't see the error if it's just a class structure doesn't match JSON error. But I doubt it since it's the very same class structure I'm using to create the JSON.
If anyone can point me in the right direction, I'd be most greateful.
I've created a dotnetfiddle to avoid clutching the question with huge pieces of code. Here's the link: Fiddle
I generate that JSON with a console application that gets info on the DB schema. I use a common project with all the entities defined in it to load the data in memory and then generate the JSON from that structure. Then I use the same project with the same entities on another application to compare another DB schema to the JSON log. That application is unable to deserialize the JSON. Tried to provide a minimal example with a single class and as you can see on the fiddle...that doesn't deserialize either.
It is my understanding that ObservableCollections should in fact serialize and deserialize without issues, and that INotifyPropertyChange should not cause issues (as long as you're not trying to fire an event with a null reference). So...anyone has any idea what's going on here?.
EDIT: Forgot to mention. Notice how only the base type string gets deserialized...so it IS running some deserialization, just not of classes like ObservableCollection or user classes. Maybe that helps somehow to pinpoint the issue.
EDIT2: Added a trace writer and the JSON.Net trace is detecting the right type for the objects, so I'm guessing the issue is on converting types or initializing some of the types
The problem is in how your property getters work combined with the default ObjectCreationHandling setting in Json.Net. Allow me to explain:
By default, if a reference property has an existing (non-null) value during deserialization, Json.Net tries to reuse the existing instance and populate it instead of creating a new instance. To find out whether the property has a value, Json.Net calls the getter. In your case, the getter returns a new instance when the backing field is null, but, critically, it does not set the backing field to the new instance:
get { return _header ?? new StoredProcedureDataHeader(); }
Json.Net then populates the new instance. Because the backing field was never set to the new instance, that instance ultimately gets thrown away. Json.Net never calls your setter because it assumes that your object already has a reference to the new instance, since it got that instance from the getter. Then, when you next call that getter after deserialization, you get a new, empty instance back instead of what you were expecting.
There are two ways to fix the problem:
Change your getters to set the backing field whenever a new instance is created, for example:
get
{
if (_header == null)
{
_header = new StoredProcedureDataHeader();
}
return _header;
}
OR
Change the ObjectCreationHandling setting to Replace to force Json.Net to always create new instances when deserializing. Json.Net will then call the setter and not the getter, which I think is what you want.
var settings = new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Replace
};
var data = JsonConvert.DeserializeObject<StoredProcedureData>(json, settings);
In your case, I would actually recommend that you apply both fixes. If you don't fix your getters (option 1), you could run into a similar issue elsewhere in your code. For example, you might have something like this:
var data = new StoredProcedureData();
data.Header.SPName = "foo";
if (data.Header.SPName == "foo")
{
Console.WriteLine("foo");
}
else
{
Console.WriteLine("oops");
}
Guess which value will be printed?
And option 2 will protect against possibly unexpected results if you happen to have initialized a collection somewhere to have a default set of values. For example, if you had something like this:
public StoredProcedureData()
{
_funcRef = new ObservableCollection<string>();
_funcRef.Add("Initialize");
}
then when you deserialize, you will get the default values plus the values from the JSON, which is probably not what you want. Setting ObjectCreationHandling to Replace will ensure that you will end up with just the values which were deserialized from the JSON.
I have a function that returns a Dictionary<uint, SomeClass> this function is called every second updating data to my list.
Right now, used like this to update my property:
MyData = Api.GetData();
And my property as:
public static Dictionary<uint, SomeClass> MyData { get; private set; }
Is that method fine to update my Dictionary or how should it be done?
I mean, the Dictionary is constantly being replaced as it is right now, right? So if I am using or updating any entry of that Dictionary say:
MyData[SomeValidKey].SomeProperty
My reference would become null or invalid? Or it would simple use a copy of it? Or this is something that would only have a chance to ever happen depending on how fast MyData is queried and the such?
What would be an optimal way to update my Dictionary, while allowing other parts of my application to freely access and use it?
The dictionary is mainly read only and/or call functions of a given item in the Dictionary that is part SomeClass.
UPDATE:
Since MyData = Api.GetData(); means the list is actually replaced? If so if an entry that previously existed no longer exist but any of my functions still had it in use, it would cause exceptions? If an item that was previously used is updated I would not have the updated data as my reference is dead?
So the way I am updating my Dictionary is clearly wrong?
If you're updating your Dictionary in a separate thread then you should use proper locking mechanism to ensure that you're reading the current value. Use lock for both read/write. Also there is a ConcurrentDictionary class in .NET 4 (or above) which is designed for concurrent operations.
But if you're using your dictionary in a single thread then you shouldn't worry about locking at all. Here is an example to demonstrate what happens when you change the reference to another someClass instance:
private class SomeClass
{
public string Name { get; set; }
}
...
Dictionary<uint, SomeClass> dic = new Dictionary<uint, SomeClass>
{
{ 1u, new SomeClass { Name = "1"}},
{ 2u, new SomeClass { Name = "2"}}
};
var sc1 = dic[1]; // sc1 refers to old instance of SomeClass
dic[1] = new SomeClass { Name = "new" }; // now we change the reference here
string oldName = sc1.Name; // oldName is still "1", because sc1 points to the old instance
Your question is different to your example. Your example states you are replacing your dictionary when you call your API. Your question corresponds to updating.
If you were to update your dictionary, then you can either assign the return of your Api call to a temporary dictionary, then transfer/add/delete values in MyData or pass MyData to your Api function and handle that functionality there. This would keep your references in tact if accessed from other parts of your application.
If this isn't possible, then you cannot guarantee that there aren't to be errors from other parts of your code when you replace your MyData object with your Api call. The easiest solution here would that you do not cache your MyData entry value but instead cache its key. Other parts of your application can then check if their cached key is valid and take appropriate action.
I'm creating two objects and assign them with a data from IsolatedStorage.
But when I change one object the second one changes too. ( I think the problem may be the pointers are the same, but I can't solve it. )
private ArrayOfClsSimpleData lstUsers;
private ArrayOfClsSimpleData tmpLstUsers;
in class' globals
tmpLstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
The first status of the arrays:
Debug.Write(lstUsers.Count)
Output: 2
Debug.Write(tmpLstUsers.Count)
Output: 2
The counts are the same as expected. But, after I add an item to one list, the other list gets updated too and the counts are still same.
lstUsers.Add(new ArrayOfClsSimpleData());
Debug.Write(lstUsers.Count)
Output: 3
Debug.Write(tmpLstUsers.Count)
Output: 3
EDIT : IsolatedStorageHelper class is something to help to get objects, save object etc. that I do use for simplifying things, so just think it as getting objects from IsolatedStorage.
it is implemented like this:
public static T GetObject<T>(string key)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
return (T)IsolatedStorageSettings.ApplicationSettings[key]; // return the object
}
return default(T); // if key doesn't exists , return default object
}
So it just gets it from IsolatedStorage.
If you don't know isolated storage you can see it from here
So, how can I fix the code so that I can change one without changing the other?
So, basically lstUsers and tmpLstUsers are references to the same object. All you have to do is to create a new one and copy content from the original. If you need a quick solution, then you can do it like this (code below). I just guess that ArrayOfClsSimpleData is some kind of array.
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey");
tmpLstUsers = new ArrayOfClsSimpleData();
foreach (object user in lstUsers) // I don't know the type of objects in ArrayOfClsSimpleData, so I wrote 'object', but you should use the actual type
tmpLstUsers.Add(user);
The problem is that IsolatedStorage is just returning two pointers to the same data. So unless you copy the data, all changes will ultimately be to the same underlying data.
Think of it as two copies of your home address. Anything you change on your home affects all copies of your address since it is just an address and not the home itself.
What you will want to do is clone your object. Built in collections have clone or copy methods built in to do shallow copies, or if you built something yourself you will need to implement it yourself
The easiest way is to implement the IClonable interface and to use the clone method to achieve your copying.
https://msdn.microsoft.com/en-us/library/System.ICloneable.aspx
This basically involves going through and calling member wise clone for each complex object (which will copy all value types for you)
https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
I don't think cloning is necessary. Just create a new list instead of operating on the same instance. You can do that by calling ToList() on the returned instance:
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey").ToList();
Can't you use the Clone() method of IClonable while fetching the object? looks like both list objects are getting same reference objects.
I have a service that is returning a custom object called "UserSettings" In my application I want to add more properties to the "UserSettings" object so I created a new object called "MyUserSettings" that inherits from "UserSettings" now I want to populate my new object with the existing data held in "UserSettings" and the new data I have for my new properties. I do not want to have to map each property one by one to the same property in the new object like this..
_MyUserSettings.Name=_UserSettings.Name;
Is there a way or better approach to what I am doing to populate ALL the properties of the existing object into my new object in one shot??
Yes, you can use Copy Constructor pattern. It would give you an other benefit - you do not need public property setters so object becomes immutable.
public MyUserSettings(UserSettings baseSettings)
{
// TODO: set all properties
}
Unfortunately this is the only way, however, the specific mechanism can change. There are a numerous ways (not listing them all):
Copy constructor, that takes an item and does this manual copying of fields across.
Use reflection to have a more generic mechanism of achieving the same.
Use something like AutoMapper.
They all boil down to pretty much doing the same thing.
If the UserSettings is actually a MyUserSettings then you can simply cast it:
var mySettings = (MyUserSettings)settings;
However, this will fail if UserSettings is really UserSettings.
I am using Nhibernate (I am a complete noob), and what I want to be able to do is copy an entity that is loaded from the database and save it with a new Id... has anyone run into this situation? Any help would be very appreciated.
Just do new MyClass() and copy everything except the Id. You can use reflection for that.
I need to do exactly this for a very complex set of objects and what I have found so far is:
NHibernate does not exactly support this.
If you try to simply replace the Id of an object you got from a session, you will get an Nhibernate error: identifier of an instance of was altered from <9ae3868d-17bf-4314-ba0c-4eb3b44b1a2e> to <2b2b67c6-a421-48c4-836c-4c27f6481718>
If the session no longer knows about the objects it retrieved, i.e if you evict them before saving and flushing, just changing the ids will now work. So you could write code like this:
public void CloneStudent(Guid studentId)
{
// Get existing student
Student student = _session.Get<Student>(studentId);
// Copy by reference
Student newStudent = student;
// Reset Id to do quick and dirty clone
newStudent.Id = Guid.NewGuid();
newStudent.Sticker = "D";
// Must evict existing object or Nhibernate will throw object modified error
_session.Evict(student);
// Save new object
_session.Save(newStudent);
_session.Flush();
}
The problem with this is if your object graph has any depth you have to be sure to evict the entire set, and then you may need the originals in the session still you have to retrieve them again. This is a logistical headache and yields code with very obscure and convoluted intentions.
I do not recommend.
What is more commonly done is serialize to a binary stream and reconstitute this stream into a new set of objects. Fine, but only works if your objects are all serializable.
That is not the case for me, what I am doing is I wrote manual code to make deep copies of an object graph using copy constructors. This is complex and also can lead to maintenance issues, but if the objects cannot be serialized there are few better alternatives.
Sorry, deep copying objects remains a complicated task if serialization is not an option.