2010-10-11 30 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域實體。

相關問題