如何在NHibernate中正确映射无符号数据类型
本文关键字:映射 无符号 数据类型 NHibernate | 更新日期: 2023-09-27 17:50:12
我想知道如何将UInt16值映射到相应的数据库类型而没有大的模糊。
我们正在使用Microsoft SQL Server Compact 3.5, NHibernate和FluentNHibernate进行配置。
直接的方法-将导致错误
public class Identificator
{
public Identificator( ushort componentType, ushort componentID ) { ... }
public virtual ushort ComponentType { get; protected set; }
public virtual ushort ComponentID { get; protected set; }
...
}
public class IdentificatorMapping : ClassMap<Identificator>
{
public IdentificatorMapping()
{
this.Map( x => x.ComponentType );
this.Map( x => x.ComponentID );
...
}
}
当实际在数据库上创建一个新对象时…
// Create Object
Identificator persistableObjectOK = new Identificator( 0x0001, 0x0001 );
// Persist it
ISession session = GetSession();
session.Save( persistableObjectOK );
…我将得到这个错误,这是OK的,因为SQL Server CE不知道unsigned类型
FluentNHibernate.Cfg。FluentConfigurationException:创建SessionFactory时使用了无效或不完整的配置。查看PotentialReasons集合和InnerException获取更多细节。
系统。ArgumentException: Dialect不支持DbType。UInt16
Using CustomSqlType - works part
所以,我去强迫NHibernate在数据库上取一个4字节长的整数,所以应该涵盖UInt16
的数据范围public class IdentificatorMapping : ClassMap<Identificator>
{
public IdentificatorMapping()
{
this.Map( x => x.ComponentType ).CustomSqlType( "INTEGER" );
this.Map( x => x.ComponentID ).CustomSqlType( "INTEGER" );
...
}
}
结果是工作…只要我保持在32767以下!超过这个值,整个东西就会爆炸。
奇怪的是,在应用程序中,它是无符号的2字节。
两者都应该足以存储65536
然而,NHibernate还没有被说服。在数据库的某个地方,它试图将UInt16转换为Int16。
System.Convert.ToInt16(UInt16 value)
System.UInt16.System.IConvertible.ToInt16(IFormatProvider provider)
System.Data.SqlServerCe.Accessor.set_Value(Object value)
System.Data.SqlServerCe.SqlCeCommand.FillParameterDataBindings(Boolean verifyValue)
System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery()
NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
NHibernate.Id.Insert.AbstractSelectingDelegate.PerformInsert(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder)
NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Boolean[] notNull, SqlCommandInfo sql, Object obj, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Object obj, ISessionImplementor session)
NHibernate.Action.EntityIdentityInsertAction.Execute()
NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.FireSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.SaveOrUpdate(String entityName, Object obj)
NHibernate.Engine.CascadingAction.SaveUpdateCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
NHibernate.Engine.Cascade.CascadeToOne(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
NHibernate.Engine.Cascade.CascadeAssociation(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
NHibernate.Engine.Cascade.CascadeProperty(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
NHibernate.Event.Default.AbstractSaveEventListener.CascadeBeforeSave(IEventSource source, IEntityPersister persister, Object entity, Object anything)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.Save(Object obj)
具体问题:我怎么能说NHibernate不做这个转换,而是从un16转换到Int32 ?
与这个答案类似,我创建了一个将UInt16存储在Int16中的用户类型。代价是,如果我们超过32K,数据库中的表示可能看起来错误(即显示负值)。
using System;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;
public class UInt16UserType : IUserType
{
public Object NullSafeGet( System.Data.IDataReader rs, String[] names, Object owner )
{
Int16? i = (Int16?) NHibernateUtil.Int16.NullSafeGet( rs, names[0] );
return (UInt16?) i;
}
public void NullSafeSet( System.Data.IDbCommand cmd, Object value, int index )
{
UInt16? u = (UInt16?) value;
Int16? i = (Int16?) u;
NHibernateUtil.Int16.NullSafeSet( cmd, i, index );
}
public Type ReturnedType
{
get
{
return typeof(Nullable<UInt16>);
}
}
public SqlType[] SqlTypes
{
get
{
return new SqlType[] {SqlTypeFactory.Int16};
}
}
public Object Assemble( Object cached, Object owner )
{
return cached;
}
public Object DeepCopy( Object value )
{
return value;
}
public Object Disassemble( Object value )
{
return value;
}
public int GetHashCode( Object x )
{
return x.GetHashCode();
}
public bool IsMutable
{
get
{
return false;
}
}
public Object Replace( Object original, Object target, Object owner )
{
return original;
}
public new bool Equals( Object x, Object y )
{
if (Object.ReferenceEquals( x, y ))
{
return true;
}
if (x == null || y == null)
{
return false;
}
if (!(x is UInt16 && y is UInt16))
{
return false;
}
UInt16 a = (UInt16) x;
UInt16 b = (UInt16) y;
bool result = a == b;
return result;
}
}
SQL Server(包括CE)不支持unsigned类型,所以没有有效的类型可以转换。例外是byte/tinyint。
你可以编写一个自定义的IUserType实现来完成ushort和int的转换,但是在你的代码中使用int会简单得多。
参见:使用小数据类型(例如short而不是int)是否会减少内存使用?