3

基于Jimmy's Enumeration classes 的想法,我想看看我是否可以避免使用构造函数来实例化我的类型(我假设发生discriminator-value在.

这是我的类型:

public class Impact : Enumeration
{
    public static readonly Impact Carbon
        = new Impact(1, "Carbon dioxide equivalent", CommonUnit.CO2e);
    public static readonly Impact Energy
        = new Impact(2, "Energy", CommonUnit.MJ);
    public static readonly Impact Cost
        = new Impact(3, "Cost", CommonUnit.Dollars);



    public Impact(int index, string name, CommonUnit unit)
        : base(index, name)
    {
        this.Unit = unit;
    }


    public CommonUnit Unit { get; private set; }

}

这是 的定义Enumeration

public class Enumeration : ValueObject
{
    public Enumeration(int index, string displayName)
    {
        this.Index = index;
        this.DisplayName = displayName;
    }


    public int Index { get; private set; }
    public string DisplayName { get; private set; }


    public override string ToString()
    {
        return this.DisplayName;
    }


    public static IEnumerable<T> GetAllFor<T>() where T : Enumeration
    {
        foreach (var publicStatic in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly))
        {
            Enumeration item = null;
            item = (Enumeration)publicStatic.GetValue(null);
            yield return item as T;
        }
    }

    public static T With<T>(int index) where T : Enumeration
    {
        return GetAllFor<T>().SingleOrDefault(i => i.Index == index);
    }
}

ValueObject简单地涵盖了平等功能。

在其他地方,我使用静态方法从这个枚举中获取项目(有点像你如何使用核心枚举静态方法):

impact = Impact.With<Impact>(index.ImpactId.Value);

这非常方便,但我想知道是否可以让 NHibernate 在为对象补水时也这样做。

可以做到吗?怎么做?

4

2 回答 2

4

使用 NHibernate 自定义类型:

public class EnumerationType<T> : PrimitiveType where T : Enumeration
{
    public EnumerationType()
        : base(new SqlType(DbType.Int32))
    {
    }

    public override object Get(IDataReader rs, int index)
    {
        object o = rs[index];
        var value = Convert.ToInt32(o);
        return Enumeration.With<T>(value);
    }

    public override object Get(IDataReader rs, string name)
    {
        int ordinal = rs.GetOrdinal(name);
        return Get(rs, ordinal);
    }

    public override Type ReturnedClass
    {
        get { return typeof(T); }
    }

    public override object FromStringValue(string xml)
    {
        return int.Parse(xml);
    }

    public override string Name
    {
        get { return "Enumeration"; }
    }

    public override void Set(IDbCommand cmd, object value, int index)
    {
        var parameter = (IDataParameter)cmd.Parameters[index];

        var val = (Enumeration)value;

        parameter.Value = val.Value;
    }

    public override string ObjectToSQLString(object value, Dialect dialect)
    {
        return value.ToString();
    }

    public override Type PrimitiveClass
    {
        get { return typeof(int); }
    }

    public override object DefaultValue
    {
        get { return 0; }
    }
}

如果您正在执行基于 HBM.xml 的映射,则可以像这样设置自定义类型:

<property name="Impact" column="Impact" type="Namespace.To.EnumerationType`1[[Impact, AssemblyWithDomainEnum]], AssemblyWithNHibCustomType"/>

或者,如果您使用 Fluent NHibernate,您可以创建一个约定来映射所有枚举类型,而无需单独配置每个枚举类型:

public class EnumerationTypeConvention : IPropertyConvention, IPropertyConventionAcceptance
{
    private static readonly Type _openType = typeof(EnumerationType<>);

    public void Apply(IPropertyInstance instance)
    {
        var closedType = _openType.MakeGenericType(instance.Property.PropertyType);

        instance.CustomType(closedType);
    }

    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => typeof(Enumeration).IsAssignableFrom(x.Property.PropertyType));
    }
}

然后在 Fluent NHibernate 配置中添加您喜欢的约定。

于 2012-05-01T12:26:47.630 回答
1

这似乎也有效,但也许吉米的方式似乎更容易:

public class ImpactEnumType : IUserType
{
    public SqlType[] SqlTypes
    {
        get
        {
            //We store our Impact in a single column in the database that can contain a int (for the index value)
            SqlType[] types = new SqlType[1];
            types[0] = new SqlType(DbType.Int32);
            return types;
        }
    }

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

    public bool Equals(object x, object y)
    {
        // Impact is derived from ValueObject which implements Equals
        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        // as above
        return x.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        //We get the string from the database using the NullSafeGet used to get ints
        int impactIndex = (int)NHibernateUtil.Int32.NullSafeGet(rs, names[0]);

        // then pull the instance from the Enumeration type using the static helpers
        return Impact.With<Impact>(impactIndex);
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        //Set the value using the NullSafeSet implementation for int from NHibernateUtil
        if (value == null)
        {
            NHibernateUtil.Int32.NullSafeSet(cmd, null, index);
            return;
        }
        value = (value as Impact).Index;
        NHibernateUtil.Int32.NullSafeSet(cmd, value, index);
    }

    public object DeepCopy(object value)
    {
        //We deep copy the Impact by creating a new instance with the same contents
        if (value == null) return null;
        return Impact.With<Impact>((value as Impact).Index);
    }

    public bool IsMutable
    {
        get { return false; }
    }

    public object Replace(object original, object target, object owner)
    {
        //As our object is immutable we can just return the original
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        //Used for casching, as our object is immutable we can just return it as is
        return cached;
    }

    public object Disassemble(object value)
    {
        //Used for casching, as our object is immutable we can just return it as is
        return value;
    }
}

我的 HBM XML:

<property name="Impact" column="ImpactIndex" type="namespace.childnamespace.ImpactEnumType, namespace.childnamespace" />
于 2012-05-03T07:28:48.053 回答