2012-04-04 15 views
5

He la siguiente tabla:¿Cómo correlacionar la columna de tipo XML a una propiedad de objeto fuertemente tipada con NHibernate?

CREATE TABLE [dbo].[Data] (
    [Id]   UNIQUEIDENTIFIER NOT NULL, 
    [Data] XML    NOT NULL, 
); 

Necesito hacer un mapa del objeto:

class Data 
{ 
    public virtual Guid Id {get; set;} 
    public virtual StronglyTypedData Data {get; set;} 
} 

Cuando, StronglyTypedData es algo así como:

class StronglyTypedData 
{ 
    public string Name {get; set;} 
    public int Number {get; set;} 
} 

Por defecto, las columnas XML se asignan a las propiedades de XmlDocument, pero me gustaría que la serialización/deserialización de XML a la propiedad StronglyTypedData ocurra en su lugar en el momento del mapeo.

¿Qué debo hacer para lograr esto?

Respuesta

4

Necesita escribir un IUserType que se encargue de la conversión.

Puede comenzar desde XmlDocType, que es el que realmente convierte de XML sin procesar a XmlDocument.

+0

Una cosa que sé Quiero evitar está usando XmlDocument. Suena como una sobrecarga innecesaria. Preferiría serializar/deserializar directamente entre XML sin formato y objetos muy tipados, es decir, usar XmlSerializator en lugar de XmlDoc. – tishma

+1

Sugiero que mires XmlDocType ** como ejemplo **, porque tu implementación será similar. –

+0

Ya veo. Le echaré un vistazo. Gracias. – tishma

8

Iba a hacer un comentario sobre la publicación de Diego, pero era demasiado largo y quería resaltar la sintaxis. Modifiqué el XmlDocType que Diego publicó para que utilizara la serialización xml hacia y desde un objeto fuertemente tipado.

hice mi propia IUserType genérica para manejar el tipado fuerte:

//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); 
     } 
    } 

} 

Entonces, finalmente, puede utilizar Fluent.NHibernate para mapear la columna así:

public partial class MyTableEntityMap: ClassMap<MyTableEntity> 
{ 
    public MyTableEntityMap() 
    { 
     Table("MyTable"); 
     //... 

     Map(x => x.MyStronglyTypedProperty).Column("SomeXmlTypeSqlColumn").CustomType(typeof(XmlType<TypeOfMyProperty>)); 
    } 
} 
+0

¡Amigo, eres un salvavidas! –

Cuestiones relacionadas