我正在尝试在我的控制台应用程序中实现一些适当的NHibernate会话管理,但遇到了一些非常奇怪的问题。有一刻,一切似乎工作正常,但是随机,突然它在尝试获取一个似乎指向日期时间值的特定对象时开始抛出“指定的强制转换无效”异常,但没有更多的信息是提供。
现在,我已经消除了映射出错的可能性,因为除了字符串字段和主键(它是GUID)之外,我只是简单地取消了所有字段的注释。尽管如此,例外仍然被抛出。此外,有问题的对象不包含任何子对象。
相反,我怀疑我调用Session的方式有问题,所以Session的缓存中有一些东西导致这个问题出于某种模糊的原因。
我使用此Util类来管理会话:
public static class FcoNHibernateUtil
{
private static readonly ISessionFactory sessionFactory = BuildSessionFactory();
private static ISessionFactory BuildSessionFactory()
{
try
{
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration()
.Configure()
.AddAssembly("FcoPersistence")
.AddAssembly("FcoLib")
.AddAssembly("FargoLib")
.BuildSessionFactory();
}
catch (Exception ex)
{
throw ex;
}
}
public static ISessionFactory GetSessionFactory()
{
return sessionFactory;
}
public static ISession GetCurrentSession()
{
if (!CurrentSessionContext.HasBind(GetSessionFactory()))
CurrentSessionContext.Bind(GetSessionFactory().OpenSession());
return GetSessionFactory().GetCurrentSession();
}
public static void DisposeCurrentSession()
{
ISession currentSession = CurrentSessionContext.Unbind(GetSessionFactory());
if (currentSession != null)
{
currentSession.Close();
currentSession.Dispose();
}
}
}
因此,在我的DataObjectManager类的每个操作开始时,我从一个从超类中继承的公共方法获取会话,该方法像这样获取会话:
public ISession GetSession()
{
return FcoNHibernateUtil.GetCurrentSession();
}
当完成控制台应用程序(或单元测试)的一次扫描中的所有操作时,我确保调用DisposeCurrentSession方法。
是否有任何可以改进的东西可以阻止这些例外的到来?
编辑
这是堆栈跟踪:
at NHibernate.Type.DateTimeType.IsEqual(Object x, Object y) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\DateTimeType.cs:line 93
at NHibernate.Type.NullableType.IsEqual(Object x, Object y, EntityMode entityMode) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\NullableType.cs:line 368
at NHibernate.Type.AbstractType.IsSame(Object x, Object y, EntityMode entityMode) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\AbstractType.cs:line 218
at NHibernate.Type.AbstractType.IsDirty(Object old, Object current, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\AbstractType.cs:line 110
at NHibernate.Type.NullableType.IsDirty(Object old, Object current, Boolean[] checkable, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\NullableType.cs:line 338
at NHibernate.Type.TypeHelper.FindDirty(StandardProperty[] properties, Object[] currentState, Object[] previousState, Boolean[][] includeColumns, Boolean anyUninitializedProperties, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Type\TypeHelper.cs:line 227
at NHibernate.Persister.Entity.AbstractEntityPersister.FindDirty(Object[] currentState, Object[] previousState, Object entity, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 3555
at NHibernate.Event.Default.DefaultFlushEntityEventListener.DirtyCheck(FlushEntityEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEntityEventListener.cs:line 456
at NHibernate.Event.Default.DefaultFlushEntityEventListener.IsUpdateNecessary(FlushEntityEvent event, Boolean mightBeDirty) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEntityEventListener.cs:line 187
at NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEntityEventListener.cs:line 43
at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 161
at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 60
at NHibernate.Event.Default.DefaultAutoFlushEventListener.OnAutoFlush(AutoFlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultAutoFlushEventListener.cs:line 30
at NHibernate.Impl.SessionImpl.AutoFlushIfRequired(ISet`1 querySpaces) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1145
at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1903
at NHibernate.Impl.CriteriaImpl.List(IList results) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\CriteriaImpl.cs:line 265
at NHibernate.Impl.CriteriaImpl.List[T]() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\CriteriaImpl.cs:line 276
at FcoPersistence.GlobalLoginSettingsManager.GetGlobalLoginSettings(String ownIdent) in C:\Users\steemfe1\Documents\Work\Code\Epimetheus\branches\Refactoring\FcoPersistence\GlobalLoginSettingsManager.cs:line 189
发生的方法:
public GlobalLoginSettings GetGlobalLoginSettings(string ownIdent)
{
session = GetSession();//if(session == null) session = Factory.OpenSession();
ITransaction tx = session.BeginTransaction();
GlobalLoginSettings owner;
try
{
ICriteria criteria = session.CreateCriteria(typeof (GlobalLoginSettings));
criteria.Add(Restrictions.Eq("OWNIdent", ownIdent));
var owners = criteria.List<GlobalLoginSettings>(); //<--- exception thrown
tx.Commit();
owner = owners.Count > 0 ? owners[0] : null;
}
catch (Exception e)
{
tx.Rollback();
throw e;
}
return owner;
}
EDIT2:
我得到一个线索,那就是在获取对象时自动刷新会话时会发生这种情况。因此看起来错误发生在早期事务中驻留在会话中的对象上,但尚未刷新。所以这个问题潜伏在会话中,直到它再次被使用。
答案 0 :(得分:0)
最简单的方法是在某处提取NHibernate源代码,将Visual Studio指向它并检查哪个值在转换为DateTime
时抛出异常。然后在调用堆栈中执行一些步骤以找到值所在的对象。这样您就可以找到错误。
答案 1 :(得分:0)
我不是要重新使用Session,而是使用SessionFactory。这有帮助。