0

如果我不映射Color而是映射具有 Color 属性的对象,则FluentNHibernate成功将其映射到varbinary(max). 但是,考虑到实际上Color仅由 4 个字节组成,并且我热衷于改进它而不使用新类型来代理它,这是非常低效的。

它内部Color由四个属性组成,

  1. long value(向下转换int为代表 ARGB)
  2. short state, 指示这是否是已知且有效的颜色
  3. string name, 颜色的名称(如果已知)。
  4. short knownColor指示它是哪种已知颜色的值

所以我试图将其映射如下。

public ColorMapping()
{
    CompositeId()
        .KeyProperty(c => Reveal.Member<Color, long>("value"))
        .KeyProperty(c => Reveal.Member<Color, short>("state"))
        .KeyProperty(c => Reveal.Member<Color, string>("name"))
        .KeyProperty(c => Reveal.Member<Color, short>("knownColor"));
}

但是,在使用时出现以下异常,

类初始化方法 DataContextTest.ClassInitialise 抛出异常。FluentNHibernate.Cfg.FluentConfigurationException:FluentNHibernate.Cfg.FluentConfigurationException:创建 SessionFactory 时使用了无效或不完整的配置。检查 PotentialReasons 集合和 InnerException 了解更多详细信息。

---> FluentNHibernate.Cfg.FluentConfigurationException:创建 SessionFactory 时使用了无效或不完整的配置。检查 PotentialReasons 集合和 InnerException 了解更多详细信息。

---> NHibernate.MappingException:无法编译映射文档:(XmlDocument)---> NHibernate.MappingException:无法确定类型:System.Linq.Expressions.Expression 1[[System.Func2[[System.Drawing.Color, System.绘图,版本=4.0.0.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a],[System.Int64,mscorlib,版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089]],mscorlib,版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089]],System.Core,版本=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089,对于列:NHibernate.Mapping.Column(Member)。

我在滥用Reveal吗?如果是这样,我打算如何使用它?

4

2 回答 2

1

我会将它映射为 UserType 来回转换它

// in mapping
Map(x => x.Color).Column("ColorARGB").CustomType<ColorUserType>();

[Serializable]
class ColorUserType : IUserType
{
    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

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

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

    bool IUserType.Equals(object x, object y)
    {
        var colorX = x as Color;
        var colorY = y as Color;
        return colorX == null ? colorY = null : colorX.ToArgb() == colorY.ToArgb();
    }

    public virtual int GetHashCode(object x)
    {
        var colorX = (Color)x;
        return (colorX != null) ? colorX.ToArgb() : 0;
    }

    public bool IsMutable { get { return false; } }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        return Color.FromArgb((int)NHibernateUtil.Int32.Get(rs, names[0]));
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        NHibernateUtil.Int32.Set(cmd, ((Color)value).ToArgb(), index);
    }

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

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

    public SqlType[] SqlTypes { get { return new []{ SqlTypeFactory.Int32 }; } }
}
于 2012-10-05T10:23:04.233 回答
0

最后我选择了 ICompositeUserType。代码如下,

public class ColorType : ICompositeUserType
{
    /// <summary>
    /// Get the value of a property
    /// </summary>
    /// <param name="component">an instance of class mapped by this "type"</param>
    /// <param name="property"/>
    /// <returns>
    /// the property value
    /// </returns>
    public object GetPropertyValue(object component, int property)
    {
        var color = (Color) component;
        if (property == 0)
        {
            return color.ToArgb();
        }

        return (int) color.ToKnownColor();
    }

    /// <summary>
    /// Set the value of a property
    /// </summary>
    /// <param name="component">an instance of class mapped by this "type"</param>
    /// <param name="property"/>
    /// <param name="value">the value to set</param>
    public void SetPropertyValue(object component, int property, object value)
    {
        throw new InvalidOperationException("Color is immutable");
    }

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

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

    /// <summary>
    /// Retrieve an instance of the mapped class from a IDataReader. Implementors
    ///             should handle possibility of null values.
    /// </summary>
    /// <param name="dr">IDataReader</param>
    /// <param name="names">the column names</param>
    /// <param name="session"/>
    /// <param name="owner">the containing entity</param>
    /// <returns/>
    public object NullSafeGet(IDataReader dr, string[] names,
        ISessionImplementor session, object owner)
    {
        var argb = (int?) NHibernateUtil.Int32.NullSafeGet(dr, names[0]);
        var knownColor = (int?) NHibernateUtil.Int32.NullSafeGet(dr, names[1]);
        return knownColor != null
            ? Color.FromKnownColor((KnownColor) knownColor.Value)
            : Color.FromArgb(argb.Value);
    }

    /// <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.
    ///             If a property is not settable, skip it and don't increment the index.
    /// </summary>
    /// <param name="cmd"/>
    /// <param name="value"/>
    /// <param name="index"/>
    /// <param name="settable"/>
    /// <param name="session"/>
    public void NullSafeSet(IDbCommand cmd, object value, int index,
        bool[] settable, ISessionImplementor session)
    {
        var color = (Color) value;
        if (color.IsKnownColor)
        {
            ((IDataParameter) cmd.Parameters[index]).Value = DBNull.Value;
            ((IDataParameter) cmd.Parameters[index + 1]).Value = (int) color.ToKnownColor();
        }
        else
        {
            ((IDataParameter) cmd.Parameters[index]).Value = color.ToArgb();
            ((IDataParameter) cmd.Parameters[index + 1]).Value = DBNull.Value;
        }
    }

    /// <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/>
    public object DeepCopy(object value)
    {
        return value;
    }

    /// <summary>
    /// Transform the object into its cacheable representation.
    ///             At the very least this method should perform a deep copy.
    ///             That may not be enough for some implementations, 
    ///             method should perform a deep copy. 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>
    /// <param name="session"/>
    /// <returns/>
    public object Disassemble(object value, ISessionImplementor session)
    {
        return value;
    }

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

    /// <summary>
    /// During merge, replace the existing (target) value in the entity we are merging to
    ///             with a new (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. However, since
    ///             composite user types often define component values, it might make sense to recursively
    ///             replace component values in the target object.
    /// </summary>
    public object Replace(object original, object target, ISessionImplementor session, object owner)
    {
        return original;
    }

    /// <summary>
    /// Get the "property names" that may be used in a query.
    /// </summary>
    public string[] PropertyNames { get { return new[] {"Argb", "KnownColor"}; } }

    /// <summary>
    /// Get the corresponding "property types"
    /// </summary>
    public IType[] PropertyTypes
    {
        get
        {
            return new IType[]
                   {
                       NHibernateUtil.Int32, NHibernateUtil.Int32
                   };
        }
    }

    /// <summary>
    /// The class returned by NullSafeGet().
    /// </summary>
    public Type ReturnedClass { get { return typeof (Color); } }

    /// <summary>
    /// Are objects of this type mutable?
    /// </summary>
    public bool IsMutable { get { return false; } }
}
于 2012-10-28T22:29:16.547 回答