I have the following table:
CREATE TABLE [dbo].[Data] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[Data] XML NOT NULL,
);
I need to map it to the object:
class Data
{
public virtual Guid Id {get; set;}
public virtual StronglyTypedData Data {get; set;}
}
Where, StronglyTypedData is something like:
class StronglyTypedData
{
public string Name {get; set;}
public int Number {get; set;}
}
By default, XML columns are mapped to XmlDocument properties, but I would like XML serialization/deserialization to StronglyTypedData property to happen instead at mapping time.
What do I need to do to accomplish this?
I was going to make this a comment on Diego's post, but it was too long and I wanted syntax highlighting. I modified the XmlDocType that Diego posted so that it would use xml serialization to and from a strongly typed object.
I made my own generic IUserType to handle the strong typing:
//you'll need these at the top of your file
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using NHibernate.UserTypes;
//using NHibernate.SqlTypes;
//using System.Data;
//using System.Xml;
//using NHibernate.Type;
[Serializable]
public class XmlType<T> : MutableType
{
public XmlType()
: base(new XmlSqlType())
{
}
public XmlType(SqlType sqlType)
: base(sqlType)
{
}
public override string Name
{
get { return "XmlOfT"; }
}
public override System.Type ReturnedClass
{
get { return typeof(T); }
}
public override void Set(IDbCommand cmd, object value, int index)
{
((IDataParameter)cmd.Parameters[index]).Value = XmlUtil.ConvertToXml(value);
}
public override object Get(IDataReader rs, int index)
{
// according to documentation, GetValue should return a string, at list for MsSQL
// hopefully all DataProvider has the same behaviour
string xmlString = Convert.ToString(rs.GetValue(index));
return FromStringValue(xmlString);
}
public override object Get(IDataReader rs, string name)
{
return Get(rs, rs.GetOrdinal(name));
}
public override string ToString(object val)
{
return val == null ? null : XmlUtil.ConvertToXml(val);
}
public override object FromStringValue(string xml)
{
if (xml != null)
{
return XmlUtil.FromXml<T>(xml);
}
return null;
}
public override object DeepCopyNotNull(object value)
{
var original = (T)value;
var copy = XmlUtil.FromXml<T>(XmlUtil.ConvertToXml(original));
return copy;
}
public override bool IsEqual(object x, object y)
{
if (x == null && y == null)
{
return true;
}
if (x == null || y == null)
{
return false;
}
return XmlUtil.ConvertToXml(x) == XmlUtil.ConvertToXml(y);
}
}
//the methods from this class are also available at: http://blog.nitriq.com/PutDownTheXmlNodeAndStepAwayFromTheStringBuilder.aspx
public static class XmlUtil
{
public static string ConvertToXml(object item)
{
XmlSerializer xmlser = new XmlSerializer(item.GetType());
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
xmlser.Serialize(ms, item);
UTF8Encoding textconverter = new UTF8Encoding();
return textconverter.GetString(ms.ToArray());
}
}
public static T FromXml<T>(string xml)
{
XmlSerializer xmlser = new XmlSerializer(typeof(T));
using (System.IO.StringReader sr = new System.IO.StringReader(xml))
{
return (T)xmlser.Deserialize(sr);
}
}
}
Then, finally, you can use Fluent.NHibernate to map your column like this:
public partial class MyTableEntityMap: ClassMap<MyTableEntity>
{
public MyTableEntityMap()
{
Table("MyTable");
//...
Map(x => x.MyStronglyTypedProperty).Column("SomeXmlTypeSqlColumn").CustomType(typeof(XmlType<TypeOfMyProperty>));
}
}
You need to write an IUserType
that takes care of the conversion.
You could start from XmlDocType, which is the one actually converting from raw XML to a XmlDocument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With