Nhibernate 如何在不将鉴别器传递到构造函数的情况下映射枚举类?
基于这个想法,我想看看我是否可以避免(我假设是发生在Nhibernate 如何在不将鉴别器传递到构造函数的情况下映射枚举类?,nhibernate,orm,Nhibernate,Orm,基于这个想法,我想看看我是否可以避免(我假设是发生在鉴别器值上),而是使用“工厂方法”(factory method)——类似于从数据库映射实例的方法 这是我的类型: public class Impact : Enumeration { public static readonly Impact Carbon = new Impact(1, "Carbon dioxide equivalent", CommonUnit.CO2e); public static
鉴别器值
上),而是使用“工厂方法”(factory method)——类似于从数据库映射实例的方法
这是我的类型:
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; }
}
下面是枚举的定义:
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);
}
}
这是相当方便,但我想知道我是否可以让NHibernate做这件事时,再水化对象
使用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; }
}
}
公共类EnumerationType:原语类型,其中T:枚举
{
公共枚举类型()
:base(新的SqlType(DbType.Int32))
{
}
公共重写对象Get(IDataReader rs,int索引)
{
对象o=rs[索引];
var值=转换为32(o);
返回枚举。带(值);
}
公共重写对象Get(IDataReader rs,字符串名称)
{
int ordinal=rs.GetOrdinal(名称);
返回Get(rs,序号);
}
公共重写类型ReturnedClass
{
获取{return typeof(T);}
}
公共重写对象FromStringValue(字符串xml)
{
返回int.Parse(xml);
}
公共重写字符串名
{
获取{返回“枚举”;}
}
公共覆盖无效集(IDbCommand cmd,对象值,int索引)
{
var参数=(IDataParameter)命令参数[索引];
var val=(枚举)值;
参数值=值值;
}
公共重写字符串ObjectToSQLString(对象值,方言)
{
返回值.ToString();
}
公共重写类型基元类
{
获取{return typeof(int);}
}
公共覆盖对象默认值
{
获取{返回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));
}
}
公共类枚举类型约定:IPropertyConvention,IPropertyConvention Acceptance
{
私有静态只读类型_openType=typeof(枚举类型);
公共无效应用(IPropertyInstance实例)
{
var closedType=\u openType.MakeGenericType(instance.Property.PropertyType);
实例.CustomType(closedType);
}
公共无效接受(IAcceptanceCriteria标准)
{
Expect(x=>typeof(枚举).IsAssignableFrom(x.Property.PropertyType));
}
}
然后在流畅的NHibernate配置中添加您喜欢的约定。这似乎也可行,但可能更容易:
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;
}
}
公共类ImpactEnumType:IUserType
{
公共SqlType[]SqlTypes
{
得到
{
//我们将影响存储在数据库中的一列中,该列可以包含int(用于索引值)
SqlType[]types=新的SqlType[1];
types[0]=新的SqlType(DbType.Int32);
返回类型;
}
}
公共类型返回类型
{
获取{return typeof(Impact);}
}
公共布尔等于(对象x、对象y)
{
//影响来自ValueObject,它实现了Equals
返回x等于(y);
}
公共int GetHashCode(对象x)
{
//如上
返回x.GetHashCode();
}
公共对象NullSafeGet(IDataReader rs,字符串[]名称,对象所有者)
{
//我们使用NullSafeGet从数据库中获取字符串,用于获取int
int impactIndex=(int)NHibernateUtil.Int32.NullSafeGet(rs,names[0]);
//然后使用静态帮助程序从枚举类型中提取实例
返回影响。带有(影响指数);
}
public void NullSafeSet(IDbCommand cmd,对象值,int索引)
{
//使用NHibernateUtil中int的NullSafeSet实现设置值
如果(值==null)
{
NHibernateUtil.Int32.NullSafeSet(cmd,null,index);
返回;
}
值=(作为影响的值)。索引;
NHibernateUtil.Int32.NullSafeSet(cmd,value,index);
}
公共对象深度复制(对象值)
{
//我们通过创建具有相同内容的新实例来深度复制影响
if(value==null)返回null;
返回影响。带((值作为影响)。索引);
}
公共布尔可换
{
获取{return false;}
}
公共对象替换(对象原始、对象目标、对象所有者)
{
//因为我们的对象是不可变的,所以我们可以返回原始对象
归还原件;
}
公共对象集合(对象缓存,对象所有者)
{
//用于级联,因为我们的对象是不可变的,所以我们可以按原样返回它
返回缓存;
}
公共对象(对象值)
{
//用于级联,因为我们的对象是不可变的,所以我们可以按原样返回它
返回值;
}
}
我的HBM XML:
<property name="Impact" column="ImpactIndex" type="namespace.childnamespace.ImpactEnumType, namespace.childnamespace" />
根据我在您的博客上找到的一些评论,我开始使用IUserType
。这样不行吗?似乎您对PrimitiveType
的建议在某种程度上可能与IUserType
相关联,因为方法似乎相似。是的,PrimitiveType只是使自定义用户类型更容易。请解释Fluent映射中发生的事情的附加值。对于其他:。Fluent映射约定允许我们不必像处理HBM映射那样指定自定义用户类型。使用HBM,我们必须为每个属性指定自定义用户类型。根据约定,我们只需指定一次自定义用户类型。
<property name="Impact" column="ImpactIndex" type="namespace.childnamespace.ImpactEnumType, namespace.childnamespace" />