3

ジミーの列挙型クラスのアイデアに基づいて、コンストラクターを使用して型をインスタンス化するのを避けて(これはで発生していると思い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 に答える