2010-10-11 70 views
2

我有一个包含xml列的SQL Server数据库。我需要将该xml列映射到我的域实体中的expando对象。我使用NHibernate。我如何扩展NHibernate以适应此?我假设(我是NHibernate的新手),我必须覆盖实现来获取和设置XML数据,但我不知道如何在NHibernate中做到这一点。数据库中的NHibernate XML文档Expando实体中的对象

回答

2

感谢Petr的回答,我想出了以下用户类型的初始尝试来处理expando。它工作得非常好,现在我可以为每个对象提供客户端属性。我设置了每个对象必须拥有的属性,然后每个客户端都可以添加自己的属性来满足他们的需求。

一个警告 - 我只是为了持久性目的而设置它。在这个应用程序中搜索不是必需的,因为所有查询都是针对具有非规格化数据副本的MongoDB数据库完成的。

public class ExpandoUserType : IUserType 
{ 
    public object Assemble(object cached, object owner) 
    { 
     return cached; 
    } 

    public object DeepCopy(object value) 
    { 
     return value; 
    } 

    public object Disassemble(object value) 
    { 
     return value; 
    } 

    public bool Equals(object x, object y) 
    { 
     return false; 
    } 

    public int GetHashCode(object x) 
    { 
     return 0; 
    } 

    public bool IsMutable 
    { 
     get { return false; } 
    } 

    public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner) 
    { 
     var obj = NHibernateUtil.XmlDoc.NullSafeGet(rs, names[0]); 

     if (obj == null) return null; 

     var xmldoc = (XmlDocument)obj; 

     dynamic expando = new ExpandoObject(); 

     foreach (XmlElement el in xmldoc.FirstChild.ChildNodes) 
     { 
      object val = null; 

      switch (Convert.ToString(el.Attributes["type"].InnerText).ToLower()) 
      { 
       case "string": 
        val = el.InnerText; 
        break; 

       case "int32": 
        val = Convert.ToInt32(el.InnerText); 
        break; 

       case "int16": 
        val = Convert.ToInt16(el.InnerText); 
        break; 

       case "int64": 
        val = Convert.ToInt64(el.InnerText); 
        break; 

       case "bool": 
        val = Convert.ToBoolean(el.InnerText); 
        break; 

       case "datetime": 
        val = Convert.ToDateTime(el.InnerText); 
        break; 

       case "byte": 
        val = Convert.ToByte(el.InnerText); 
        break; 

       case "decimal": 
        val = Convert.ToDecimal(el.InnerText); 
        break; 
      } 
      ((IDictionary<String, Object>)expando).Add(el.Name, val); 
     } 

     return expando; 

    } 

    /// <summary> 
    /// Transforms the expando object to an XML Document for storage in SQL. 
    /// </summary> 
    /// <param name="cmd"></param> 
    /// <param name="value"></param> 
    /// <param name="index"></param> 
    public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index) 
    { 
     if (value == null || value == DBNull.Value) 
     { 
      NHibernateUtil.String.NullSafeSet(cmd, null, index); 
     } 
     else 
     { 
      NHibernateUtil.XmlDoc.Set(cmd, expandoToXML((ExpandoObject) value, "root"), index); 
     } 
    } 

    public object Replace(object original, object target, object owner) 
    { 
     return original; 
    } 

    public Type ReturnedType 
    { 
     get { return typeof(ExpandoObject); } 
    } 

    public NHibernate.SqlTypes.SqlType[] SqlTypes 
    { 
     get { return new[] { NHibernateUtil.XmlDoc.SqlType }; } 
    } 


    private static XmlDocument expandoToXML(dynamic node, String nodeName) 
    { 
     XElement xmlNode = new XElement(nodeName); 

     foreach (var property in (IDictionary<String, Object>)node) 
     { 

      if (property.Value.GetType() == typeof(ExpandoObject)) 
       xmlNode.Add(expandoToXML(property.Value, property.Key)); 

      else 
       if (property.Value.GetType() == typeof(List<dynamic>)) 
        foreach (var element in (List<dynamic>)property.Value) 
         xmlNode.Add(expandoToXML(element, property.Key)); 
       else 
       { 
        XElement xnode = new XElement(property.Key, property.Value); 
        xnode.SetAttributeValue("type", property.Value.GetType().Name); 
        xmlNode.Add(xnode); 
       } 
     } 

     return xmlNode.GetXmlNode(); 
    } 
} 
3

您必须为您的实体创建自定义类型(IUserType)。 Here有一篇不错的文章,介绍如何将XML列从数据库转换为NHibernate域实体。

相关问题