在NHibernate IUserType上实现不同的SELECT和INSERT行为

时间:2013-02-03 19:25:20

标签: c# nhibernate nhibernate-mapping

有没有办法将Create(INSERT)行为与SELECT行为分开。

假设我有一个数据库,其中的列将返回一个类似于此字符串的字符串

Predecessors = "1,3,4,5"

在我的应用程序中,我希望通过实现IUserType

将此字符串用作int数组
public interface IIntArray
{
    int[] Items { get; set; }
}

public class IntArray : IIntArray
{
    public int[] Items { get; set; }

    public IntArray(string item)
    {
        if(string.IsNullOrEmpty(item))
            return;

        Items = System.Array.ConvertAll<string, int>(item.Split(new[] {','}), int.Parse);

        // for older .net versions use the code below
        // Items = Array.ConvertAll<string, int>(item.ToString().Split(new[] { ',' }), delegate(string str) { return int.Parse(str); });
    }
}

public class IntArrayType : IUserType
{
    #region Implementation of IUserType

    /// <summary>
    /// Compare two instances of the class mapped by this type for persistent "equality"
    /// ie. equality of persistent state
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public new bool Equals(object x, object y)
    {
        if (x == null && y == null) return true;
        if (x == null || y == null) return false;
        return x.GetType() == y.GetType();
    }

    /// <summary>
    /// Get a hashcode for the instance, consistent with persistence "equality"
    /// </summary>
    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    /// <summary>
    /// Retrieve an instance of the mapped class from a resultset.
    /// Implementors should handle possibility of null values.
    /// </summary>
    /// <param name="rs">a IDataReader</param>
    /// <param name="names">column names</param>
    /// <param name="owner">the containing entity</param>
    /// <returns></returns>
    /// <exception cref="HibernateException">HibernateException</exception>
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var value = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (value == null || (string.IsNullOrEmpty(value.ToString())))
        {
            return null;
        }

        return new IntArray(value.ToString());
    }

    /// <summary>
    /// Write an instance of the mapped class to a prepared statement.
    /// Implementors should handle possibility of null values.
    /// A multi-column type should be written to parameters starting from index.
    /// </summary>
    /// <param name="cmd">a IDbCommand</param>
    /// <param name="value">the object to write</param>
    /// <param name="index">command parameter index</param>
    /// <exception cref="HibernateException">HibernateException</exception>
    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        if (value == null)
        {
            ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
        }
        else
        {
            var state = (IIntArray)value;
            ((IDataParameter)cmd.Parameters[index]).Value = state.GetType().Name;
        }
    }

    /// <summary>
    /// Return a deep copy of the persistent state, stopping at entities and at collections.
    /// </summary>
    /// <param name="value">generally a collection element or entity field</param>
    /// <returns>a copy</returns>
    public object DeepCopy(object value)
    {
        return value;
    }

    /// <summary>
    /// During merge, replace the existing (<paramref name="target" />) value in the entity
    /// we are merging to with a new (<paramref name="original" />) value from the detached
    /// entity we are merging. For immutable objects, or null values, it is safe to simply
    /// return the first parameter. For mutable objects, it is safe to return a copy of the
    /// first parameter. For objects with component values, it might make sense to
    /// recursively replace component values.
    /// </summary>
    /// <param name="original">the value from the detached entity being merged</param>
    /// <param name="target">the value in the managed entity</param>
    /// <param name="owner">the managed entity</param>
    /// <returns>the value to be merged</returns>
    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    /// <summary>
    /// Reconstruct an object from the cacheable representation. At the very least this
    /// method should perform a deep copy if the type is mutable. (optional operation)
    /// </summary>
    /// <param name="cached">the object to be cached</param>
    /// <param name="owner">the owner of the cached object</param>
    /// <returns>a reconstructed object from the cachable representation</returns>
    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    /// <summary>
    /// Transform the object into its cacheable representation. At the very least this
    /// method should perform a deep copy if the type is mutable. That may not be enough
    /// for some implementations, however; for example, associations must be cached as
    /// identifier values. (optional operation)
    /// </summary>
    /// <param name="value">the object to be cached</param>
    /// <returns>a cacheable representation of the object</returns>
    public object Disassemble(object value)
    {
        return value;
    }

    /// <summary>
    /// The SQL types for the columns mapped by this type. 
    /// </summary>
    public SqlType[] SqlTypes { get { return new[] { NHibernateUtil.String.SqlType }; } }

    /// <summary>
    /// The type returned by <c>NullSafeGet()</c>
    /// </summary>
    public Type ReturnedType { get { return typeof(IntArray); } }

    /// <summary>
    /// Are objects of this type mutable?
    /// </summary>
    public bool IsMutable { get { return false; } }

    #endregion
}

在我的NHibernate类中,我映射到像这样的属性

public virtual IntArray Predecessors { get; set; }

和hbm映射

<property name="Predecessors" type="Example.IntArrayType, Example" />

IntArray类在读取数据时起作用,但在尝试放回原点时这不起作用。我想做的是以某种方式强制IntArray属性将IntArray.Items的值呈现为逗号分隔的字符串

string magic = string.Join(",", Predecessors.Items);

由于

1 个答案:

答案 0 :(得分:0)

这样的事情可以解决问题

public void NullSafeSet(IDbCommand cmd, object value, int index)
{
    var ints = value as IntArray;
    if(ints != null && ints.Items != null)
    {
      NHibernate.NHibernateUtil.StringClob.NullSafeSet(cmd, string.Join(", ", ints.Items), index);
    }
}