How to serialize SubSonic objects with nullable properties
Recently, I ran into the following error when trying to serialize some SubSonic generated classes.
Cannot serialize member 'XXX' of type System.Nullable`1[XXX]. XmlAttribute/XmlText cannot be used to encode complex types.
The SubSonic autogenerated classes cannot serialize nullable types such as DateTime? and GUID?. This is really a .NET serialization problem and not directly related to SubSonic, since the SubSonic library just uses the native .NET code for serialization.
Solution 1
Use SubSonic generateNullableProperties setting
One way to fix this in your SubSonic generated classes it to not generate nullable properties by adding the following to your SubSonic configuration:
generateNullableProperties="false"
By configuring SubSonic to not generate nullable properties, you've fixed your serialization problem, but if you need your values to be null, then you'll end up with more problems because now, you'll have to use MyNullablePropertyHasValue method instead of MyNullableProperty.HasValue method.
Here's what the autogenerated property looks like with generateNullableProperties set to true (default):
[XmlAttribute("MyNullableProperty")] public int? MyNullableProperty { get { return GetColumnValue<int?>("MyNullableProperty"); } set { SetColumnValue("MyNullableProperty", value); } }
Here's what the autogenerated property looks like with generateNullableProperties set to false.
[XmlAttribute("MyNullableProperty")] public int MyNullableProperty { get { int? myNullableProperty = GetColumnValue<int?>("MyNullableProperty"); if (!myNullableProperty.HasValue) return 0; return myNullableProperty.Value; } set { SetColumnValue("MyNullableProperty", value); } } [XmlIgnore] public bool MyNullablePropertyHasValue { get { return GetColumnValue<int?>("MyNullableProperty") != null; } set { int? myNullableProperty = GetColumnValue<int?>("MyNullableProperty"); if (!value) SetColumnValue("MyNullableProperty", null); else if (value && !propSupplierID.HasValue) SetColumnValue("MyNullableProperty", 0); } }
This looks to be one of the simplest changes, however, now all previous null values will be equal to 0, so that would probably mess up some of your previous logic.
Solution 2
Add ShouldSerialize methods to your partial class code
You can also add a method called ShouldSerialize{XXX} (where XXX is your property name). That method should look like:
public bool ShouldSerializeMyNullableProperty() { return MyNullableProperty.HasValue; }
I believe that this is the best technique, but it also requires that you add one method per nullable property per class generated by SubSonic. That could be a lot of work, or you could modify the base class to automatically generate this method for nullable properties.
Solution 3
Use XML Elements instead of XML Attributes
You can edit the SubSonic code to generate XML Elements instead of XML Attributes. That's not what I've doing here. I'm just going to create a new method that produces an XML output using XML elements for the class.
The following code loops through the object's properties and writes out properties and their values as a XML elements (you could modify this for XML attributes).
public new string ToXML() { StringBuilder xmlResponse = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(xmlResponse)) { writer.WriteStartElement(this.GetSchema().ClassName); foreach (TableSchema.TableColumnSetting col in this.GetColumnSettings()) { string colValue = string.Empty; string colName = this.GetSchema().GetColumn(col.ColumnName).PropertyName; if (col.CurrentValue != null) colValue = col.CurrentValue.ToString(); if (string.IsNullOrEmpty(colValue)) { writer.WriteStartElement(colName); writer.WriteEndElement(); } else { writer.WriteElementString(colName, colValue); } } writer.WriteEndElement(); } return xmlResponse.ToString(); }
When doing it this way, you won't be able to deserialize the XML without writing custom deserialization code. This code can go into your partial class code or just add it to your base class.
The output will look similar to:
<MyClassName>
<MyPropertyName>MyPropertyValue</MyPropertyName>
<MyNullableProperty />
</MyClassName>
Resources:
- Defining Default Values with ShouldSerialize and Reset Methods (MSDN)
- Serialization Strikes Back (Eric Kemp)



September 30th, 2011 - 07:54
Hi,
Where would I start with Solution 2 of this post, as I’m getting this error?
Many thanks
September 30th, 2011 - 09:13
If your nullable property is called “Something” and “SomethingElse”, then just add this to a partial class and it should work. You just need to name this method the same as your nullable property, but prefix it with “ShouldSerialize” and return the HasValue property value.
public bool ShouldSerializeSomething()
{
return Something.HasValue;
}
public bool ShouldSerializeSomethingElse()
{
return SomethingElse.HasValue;
}
More Information at http://msdn.microsoft.com/en-us/library/53b8022e.aspx
October 3rd, 2011 - 06:19
Hi,
I’ve created a partial class of the of the main class file, not the “name of table”Collection. I get the error on this Cannot serialize member ‘UeValue’ so i’ve done partial class and
public bool ShouldSerializeUeValue()
{
return UeValue.HasValue;
}
Is this right?
Thanks again.
October 4th, 2011 - 05:15
That looks right to me. It’s been a while since I ran into this problem and I don’t remember which solution I used. I also don’t know if this works properly in the new version of SubSonic. Are you using version 2.2 or 3.x?
October 4th, 2011 - 05:41
Hi,
I’m using Subsonic 2.1 Final. Solution 1 works fine, but chucks up a load of other errors in the application. Anywhere I have tried to update the database with a null value.
I’ve posted on stackflow as well and referenced this blog. Do you think upgrading subsonic might help?
Thanks
October 4th, 2011 - 05:47
I’m unsure if upgrading will help or not. Also be sure to read Eric’s post (in above article under references). I think I ended up going with solution 3, since that’s the only one that always worked for me. I also remember having various issues with the other solutions, but I thought it was my project/code related.
October 4th, 2011 - 06:41
Thanks, will do. If I change the elements from XmlAttribute to XmlElement it works fine. Thing is if I generate the code again I’ll lose the changes and have to go back and change it again.