Serialize and Deserialize Property Based on DB Value - c#

I have a simple class that has bool property. The 'Get' logic for this property executes a stored procedure to return back a bit field from a database.
I then serialize this class and save it to an XML field in a database. It saves the class and the bool property just fine, no problem.
The problem I seem to be having is when I deserialize this class. The class deserilizes just fine, but when the data that drives the bool field has been updated, it seems that the class only recognizes what was serialized in XML, and it not looking back to the database to get the new bool value (does not execute my procedure to get the newly update bit field).
My solution has been to add the XmlIgnoreAttribute attribute to this field so it isn't serialized to begin with. But I'm wondering if anyone noticed this and/or can help me understand the inner working of .NET XmlSerializer class.
Thanks!
[XmlIgnoreAttribute]
public bool IsUpdated
{
get
{
DataTable dtResults = mclsSQLServerTool.LoadDataTable("exec stp_RL_SEL_NameIsUpdated '" + mstrName + "'");
bool blnIsUpdated = Convert.ToBoolean(dtResults.Rows[0]["RU_bitIsUpdated"]);
return blnIsUpdated;
}
}

The first thing to note here is that [XmlIgnore] is redundant; XmlSerializer is simply not interested in get-only properties (except for lists), because it knows it can't deserialize them. For example:
public class SomeType
{
public string Foo { get; set; }
public string Bar { get { Console.WriteLine("get_Bar"); return "abc"; } }
static void Main()
{
var ser = new XmlSerializer(typeof (SomeType));
ser.Serialize(Console.Out, new SomeType { Foo = "def" });
}
}
outputs (minus the namespaces aliases etc):
<SomeType>
<Foo>def</Foo>
</SomeType>
(note that Bar was not called)
For deserialization, the process (for simple values, not lists) is simple: as values are found in the the incoming xml stream, resolve them to members, and assign them - i.e. a xml-deserializer is basically a glorified switch statement based on incoming xml nodes.
It will never randomly call a "set" unless the data is in the incoming xml (and the property is read/write); and when it does, it expects to assign a value.
The interesting thing in your scenario is that your "get" doesn't assign the value anywhere - there is no cache. So actually, it doesn't matter that XmlSerializer doesn't touch it - every time you access IsUpdated it will do the query. Personally I suspect that is a mistake, and could lead to aggressive and unpredictable data querying.
Many serializers support the concept of serialization callbacks, which would allow you to perform some code at the end of serialization; however, XmlSerializer does not support this. So that isn't an option.
It isn't very clear what you want to achieve, but I'd just call a method at some point.

IMHO this is a mis-use of properties. Properties should have little or no code behind them. If this code was ever used in a client-server application you could potentially be making database calls from the client. I would recommend changing this to a method call. If you want to serialize the results then store the results of the "Convert.ToBoolean" in a property. Now it is a bit clearer as to what the property value is.
Something like this...
public bool IsUpdated { get; private set; }
public bool IsDataUpdated()
{
DataTable dtResults = mclsSQLServerTool.LoadDataTable("exec stp_RL_SEL_NameIsUpdated '" + mstrName + "'");
IsUpdated = Convert.ToBoolean(dtResults.Rows[0]["RU_bitIsUpdated"]);
return IsUpdated;
}

Related

How can you get the String values from an array of objects?

I have some code that basically checks the list of queues a current business object has been through. These queues are kept in an array aptly named _queueNames of type IKeyMap, a custom object my company uses.
I would like to get the textual names of the queues, as I need to check for the presence of a particular keyword and handle it separately if it's hit that particular queue.
I was hoping I could just do something like this;
var queues = _queueNames.ToArray().ToString();
if (queues.Contains("Condition"))
DoSomethingElse();
but that just gives me the object type, rather than a collection of the values. Looking at the KeyMap object, looks like just a simple key/value pair, might there be another way to do this?
Edit: KeyMap class & interface:
public interface IKeyMap : IDisposable
{
string Ley {get;}
string Field {get;}
}
public class KeyMap : IKeyMap
{
string _key, field;
public KeyMap(string key, string field)
{
_key = key;
_field = field;
}
public override string ToString()
{
return string.Format("{0}_{1}", Key, Field);
}
public string Key { get {return _key; } }
public string Field { get {return _field; } }
}
I left out some overrides, such as hashing & the Dispose method since I've got to manually type this out, can't copy-paste from my remote session :(
Without knowing what the objects inside of _queueNames look like, there is no exact answer. One mistake being made here is that you are checking a single string representing an entire array. What you want to do is check every object in the array for some value, or convert it to a string and check that value.
Here is an example:
foreach (var item in array)
{
if (item.ToString().Contains("Condition"))
{
DoSomethingElse();
break;
}
}
Or the LINQ way:
if (array.Any(item => item.ToString().Contains("Condition")))
DoSomethingElse();
This specific example only works if the object can be converted into a string that is useful to parse. You could also be accessing a member or invoking a function on said object to get your string. We can't know without more information, but hopefully this points you in the right direction.
In your IKeyMap interface, let's add a Boolean.
public string IsSpecial { get; set; }
When you create the object, set the IsSpecial flag. Then read it later..
var queues = _queueNames.ToArray().ToString();
if (queues.IsSpecial)
DoSomethingElse();
This avoids searching for strings, which is something you want to avoid. What if one of the other queues accidently end up with that string? Or what if you change the special string in one place but forget to change it in another? Or what if the capitalization is different? Or what if the string ends up with a special character that you can't see in it?
And even better way would be with an enum instead of Boolean.
public HandleType QueueHandleType {get;set;}
public enum HandleType {Normal, Special, SuperSpecial}
I might be misreading this, but is there any reason you can't just store the queues by name in array of Key/Value pairs, or even a Dictionary? For example:
var queues = new Dictionary<string, object>();
// add your queues to the dictionary, with the key name being your queue name
queues.Add("Queue1", myQueue);
// etc.
At that point you have a couple of options. First, you don't need to loop through the total set of queues you have -- you can simply do this:
var specialQueue = queues[mySpecialQueueString];
// do something with it
Or you can use LINQ to get any queues whose name contains your special string:
var results = queues.Where(keyValuePair => keyValuePair.Key.Contains(mySpecialString)).ToArray();
That said, Mason has a point in that you might need to worry about string matching and the like. There are, of course, several ways to go about this. If all queues have a fixed name then I like to make a NameConstants class with a bunch of static strings and refer to members of that class. Or you can do things like making them all upper and comparing to that.

C# Dynamic Casting with GetType()

I've read many posts trying to accomplish similar tasks but cannot find a proper solution to my problem.
I'm trying to dynamically cast an object at runtime. (I know a lot of you are going to say it can't be done, and I'm not actually sure if it can...) My problem is that I have a dynamically created TreeView in a Windows Forms Application to display an Org Chart.
The data in the TreeView pulls from 3 tables: Departments, Jobs, Employees.
Importing the Tables as a Local DataSource gives me all 3 Tables as DataSet Objects, and templates for DataRow objects type casted to the table it comes from (including all columns as properties). (Similar to linq - except for Oracle DB)
I create TreeNode objects, use a description field from my DataRow as the TreeNode.Text Property and then attach the DataRow itself as the TreeNode.Tag property. This way, I can access the data from directly within the TreeNode simply by casting:
dsMyDataSource.DepartmentRow =
(dsMyDataSource.DepartmentRow)treeview1.SelectedNode.Tag;
I have a method that runs whenever the User selects a Node on treeview1 that populates a Details window with some of the underlying objects data. As of right now, I have a single method with a switch statement as such:
private doSomething()
{
switch(treeview1.SelectedNode.Tag.GetType().Name)
{
case "dsMyDataSource.DepartmentRow":
dsMyDataSource.DepartmentRow department =
(dsMyDataSource.DepartmentRow)treeview1.SelectedNode.Tag;
lblDetailsTitle = department.Title;
break;
case "dsMyDataSource.JobRow":
//etc...
}
}
What I want to do, is to have overloaded methods for each type and get rid of my switch statements. Like so:
this.doSomething(treeview1.SelectedNode.Tag);
Problem is, this returns a base object (thus the cast). But I don't know at compile time what type of TreeNode the User will select. Thus I want to be able to do something like:
this.doSomething((treeview1.SelectedNode.Tag.GetType())treeview1.SelectedNode.Tag);
private void doSomething(dsMyDataSource.DepartmentRow department)
{
lblDetailsTitle = department.Title;
// etc...
}
private void doSomething(dsMyDataSource.JobRow job) {..}
private void doSomething(dsMyDataSource.EmployeeRow employee) {..}
Is this possible?
You might find things cleaner if you use some meaningful objects rather than working directly off DataRows. In addition this will let you add a base class, which will make your casting problems go away.
So for example you could have
abstract class Selectable
{
public string Type { get; private set; }
public Selectable(string type) { Type = type; }
abstract void doSomething();
}
and then a type for each thing you want to select
class Department : Selectable{...}, class Job : Selectable{...}
To get the base types you will need one switch in a factory object.
public static class SelectableFactory
{
public static Selectable GetFromDataRow(DataRow dr)
{
Selectable res = null;
switch (dr.Type)
{
case "Department":
res = new Department(dr);
// etc ...
}
}
}
But you now have a collection of Selectables that can use polymorphism to do the action.
In addition to making your life easier it will make your code much easier to parse for anyone else that has to work on it in the future. It's also extensible, so when you need to add a DoSomethingElse method it's much easier to add for everything - or when you need a new type of datatable you don't disturb your UI code.

Check if a class is a new instance or has at least once property populated before saving to database

I thought this would be an easy one but I can't think of a good way to do it.
User submits a webform. Based on submitted information I build three classes and assign their properties from received data:
UserInfo userInfo = new UserInfo();
UserAddress userAddress = new UserAddress();
UserEmployer userEmployer = new UserEmployer();
Based on submitted information some classes end up being populated with properties and some do not.
What's the best way to check whether userInfo class, for example, ended up with properties assigned ? I don't want to save a particular object to the database if it doesn't have any real properties assigned and all of them are set to either null or "".
I only want to save the objects that ended up with at least one real property assigned.
ps. using NHibernate to save data to db
public interface IPersistable{
bool ShouldPersist {get;}
}
public class MyPersistable:IPersistable
{
private bool _persist;
public MyPersistable(){}
public string MyValue{
get{
return _myValue;
}
set{
_persist = true;// or validate with !IsNullOrEmpty() first
_myValue = value;
}
}
public bool ShouldPersist{
get{
return _persist;
}
}
}
You could use reflection and loop through the properties, checking each one individually.
var type = userInfo.GetType();
var properties = type.GetProperties();
or if they're fields instead of properties
var fields = type.GetFields();
Then you could check each for null or some value.
Try making an interface that all three classes implement, providing a function along the lines of shouldSave() or hasSetProperties(), which checks each data field and returns true if any of them are defined.
Maybe even a method to get all the data in a form you can easily pass into NHibernate.
Don't create an instance of that object, if you do not have any values that can be assigned to the properties of that object.
Next to that, 'UserAddress' should possibly not be an entity, but a value object.

Find out whether property setter is called in DeSerialization process

Is there a way to find out whether an object property is called as part of the DeSerialization process (e.g. by the XmlSerializationReaderXXX).
Background: A typical scenario is to disable events and complex operations in that case, until the initialization is complete.
One approach I have found, is to "interpret" the stack and look up whether the call is triggered by XmlSerializationReaderXXX, which is not so elegant IMHO. Is there anything better?
public SomeClass SomeProperty
{
get { ..... }
set
{
this._somePropertyValue = value;
this.DoSomeMoreStuff(); // Do not do this during DeSerialization
}
}
-- Update --
As Salvatore has mentioned, somehow similar to How do you find out when you've been loaded via XML Serialization?
I have a possible solution.
public class xxx
{
private int myValue;
[XmlElement("MyProperty")]
public int MyPropertyForSerialization
{
get { return this.myValue; }
set
{
Console.WriteLine("DESERIALIZED");
this.myValue = value;
}
}
[XmlIgnore]
public int MyProperty
{
get { return this.myValue; }
set
{
Console.WriteLine("NORMAL");
this.myValue = value;
}
}
}
class Program
{
static void Main(string[] args)
{
xxx instance = new xxx();
instance.MyProperty = 100; // This should print "NORMAL"
// We serialize
var serializer = new XmlSerializer(typeof(xxx));
var memoryStream = new MemoryStream();
serializer.Serialize(memoryStream, instance);
// Let's print our XML so we understand what's going on.
memoryStream.Position = 0;
var reader = new StreamReader(memoryStream);
Console.WriteLine(reader.ReadToEnd());
// Now we deserialize
memoryStream.Position = 0;
var deserialized = serializer.Deserialize(memoryStream) as xxx; // This should print DESERIALIZED
Console.ReadLine();
}
}
The trick is using the XmlIgnore, it will force the xml serializer to ignore our property, then we use XmlElement to rename the property for serialization with the name of the property we want.
The problem with this technique is that you have to expose a public property for serialization, and is in some way bad because it can virtually be called by everyone.
It will not work if the member is private, unfortunally.
It works, is not totally clean, but is thread safe and don't rely on any flag.
Another possibility is to use something like the Memento pattern.
Using the same trick you can add a property called for example Memento that returns another object that contains properties suitable only for serialization, it can makes things a little cleaner.
Did you think instead of changing approach and using DataContractSerializer? It is much more powerful and produces pure XML. It supports the OnDeserializationCallback mechanism.
Since you got a pretty complex scenario you might want to consider creating a "data core" class which will be actually serialized/deserialized using simple direct way. Then your complex object is constructed from that object and you fire all events/operations as normal. It will make sequence of deserialize -> fire events/operations more explicit and easier to understand.
There's an OnDeserializingAttribute/OnDeserializedAttribute attributes pair. You can set isDeserializing flag while object is being deserialized. I don't know if they play well with XML serialization, though.
For XML Serialization solution could be implementing IXmlSerializable and embedding such logic into the ReadXml()/WriteXml() method
To have finer control of the deserialization process you could implement IXmlSerializable interface for SomeClass - in ReadXML you can then for example have some field set a flag that you are in deserialization... this flag can then be checked in the respective methods... and on completion it needs to be reset.
Another option (though not for XML IIRC) is to implement the above via OnDeserializingAttribute and OnDeserializedAttribute .
I misunderstood the question at first, but you want to ask from within setter if you are called during deserialization. To do that, use a static flag:
[serializable]
class SomeClass
{
public static IsSerializing = false;
SomeProperty
{
set
{
if(IsSerializing) DoYouStuff();
}
}
}
and then set the flag just before the serialization:
try
{
SomeClass.IsSerializing = true;
deserializedClass = (SomeClass)serializer.Deserialize(reader);
}
finaly
{
SomeClass.IsSerializing = false; //make absolutely sure you set it back to false
}
Note that same approach can work even if you deserialize a class that contains a member of your class...
Set a breakpoint on the property, and run in debug mode. It will break at the point of access for the getter/setter that you set the breakpoint on.

Efficient (Space) Serialization for Network Transfer

I am attempting to write some infrastructure to facilitate updating objects between a server and client(s). This will likely be used in a game, however, I feel that the question is not at all specific to the game (so I have asked it here).
For security and efficiency reasons I would like the server to selectively update object properties. For example, a specific property of an object may only be useful to the client which controls that object, as such the server will only update the 'owner' with this information. Alternatively, some properties may need to be sent to all clients. To implement this I have defined a custom attribute which specifies the manner in which the network should handle the property:
[AttributeUsage(AttributeTargets.Property)]
public class NetworkParameterAttribute : System.Attribute
{
public enum NetworkParameterType
{
ServerToOwner,
ServerToAll,
ServerToOwnerView,
OwnerToServer
}
private NetworkParameterType type;
public NetworkParameterType Type
{
get
{
return type;
}
}
public NetworkParameterAttribute(NetworkParameterType Type)
{
this.type = Type;
}
}
Now in an object class I can define properties like so:
public class TestObject
{
[NetworkParameter(NetworkParameterAttribute.NetworkParameterType.ServerToAll)]
public int ID { get; set; }
[NetworkParameter(NetworkParameterAttribute.NetworkParameterType.ServerToOwner)]
public string Name { get; set; }
}
I can then write a simple function which automatically grabs a certain set of properties from an object:
public byte[] GetBytes(NetworkParameterAttribute.NetworkParameterType type)
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
foreach (PropertyInfo info in this.GetType().GetProperties())
{
foreach (object attribute in info.GetCustomAttributes(true))
{
if (attribute is NetworkParameterAttribute &&
((NetworkParameterAttribute)attribute).Type == type)
{
formatter.Serialize(stream, info.GetValue(this, null));
}
}
}
byte[] buf = new byte[stream.Length];
Array.Copy(stream.GetBuffer(), buf, stream.Length);
return buf;
}
A similar function can put the object back together on the receiving side. The issue that I am having is that the serialization is very inefficient in terms of space used. For example, grabbing the ServerToAll properties from a TestObject results in 54 bytes (whereas it could be as little as 4).
So the question: Is there a more efficient way of serializing objects to a byte stream that will work for my intended purpose? Note that I would prefer not to write a lot of serialization related code.
Thank you!
NetworkParameterAttribute should have additional field that denotes the corresponding property as "dirty". Every change to a property should effectively set this flag, and during serialization the flag should be reset. Only dirty properties should actually be serialized.
Additionally, now that the object is only partially serialized, during serialization now you need to provide the information about what properties are being serialized. Maintain one bitvector of dirty properties while you populate the stream, and put this bitvector in the beginning of returned byte array.
EDIT: Instead of having a flag inside an attribute we can have the actual value that was serialized last. The advantage is that we don't need additional code for each property to keep the flag synchronized with the property. During serialization we compare two values and serialize property if the values are not equal.

Categories

Resources