根据Jimmy's Enumeration classes想法,我想知道我是否可以避免using the constructor to instantiate my type(我假设发生在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
简单地涵盖了平等功能。
在其他地方,我使用静态方法从这个枚举中获取项目(有点像你可以使用核心Enumeration静态方法):
impact = Impact.With<Impact>(index.ImpactId.Value);
这非常方便,但我想知道在补充物体时我是否也可以让NHibernate这样做。
能做到吗?怎么做?
答案 0 :(得分: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配置中添加该约定。
答案 1 :(得分:1)
这似乎也有效,但也许Jimmy's way似乎更容易:
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" />