我想知道如何在没有大量模糊的情况下将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 );
...我会得到那个错误,这是正常的,因为SQL Server CE不知道无符号类型
FluentNHibernate.Cfg.FluentConfigurationException:创建SessionFactory时使用了无效或不完整的配置。检查PotentialReasons集合,以及InnerException以获取更多详细信息 System.ArgumentException:Dialect不支持DbType.UInt16
使用CustomSqlType - 部分工作
所以,我强迫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个字节。在数据库中,它被标记为4个字节。
两者都应足以存储多达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不做这个转换,而是从UIn16转换为Int32呢?
答案 0 :(得分:0)
SQL Server(包括CE)不支持无符号类型,因此没有要转换的有效类型。例外是byte / tinyint。
您可以编写一个自定义IUserType实现来为ushort和int进行转换,但在代码中使用int会更简单。
另请参阅:Does using small datatypes (for example short instead of int) reduce memory usage?
答案 1 :(得分:0)
与此answer类似,我创建了一个在Int16中存储UInt16的用户类型。 折价是如果我们超过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;
}
}