3

xml 列を含む SQL Server データベースがあります。その xml 列をドメイン エンティティ内の expando オブジェクトにマップする必要があります。私はNHibernateを使用しています。これに対応するためにNHibernateを拡張するにはどうすればよいですか? 私は、xml データを取得および設定するために実装をオーバーライドする必要があると想定しています (NHibernate は初めてです) が、NHibernate でそれを行う方法がわかりません。

4

2 に答える 2

5

エンティティのカスタム タイプ (IUserType) を作成する必要があります。ここには、XML 列をデータベースから NHibernate ドメイン エンティティに変換する方法に関する優れた記事があります。

于 2010-10-12T05:38:31.623 に答える
3

Petr の回答のおかげで、expando を処理するユーザー タイプで次の最初の試みを思いつきました。これは非常にうまく機能し、各オブジェクトにクライアント セット プロパティを提供できるようになりました。各オブジェクトに必要なプロパティを設定すると、各クライアントはニーズを満たすために独自のプロパティを追加できます。

1 つの注意点 - 永続化の目的でのみこれを設定しています。すべてのクエリは、データのコピーを非正規化した 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();
    }
}
于 2010-10-20T17:07:41.637 に答える