I am trying to implement some proper NHibernate session management in my console application, but running into some very weird problems. One moment everything seems to be working fine, but randomly, all of a sudden it starts throwing an "Specified cast is not valid" exception when trying to fetch a specific object which seems to be pointing to a datetime value, but no more info is provided.
开发者_JS百科Now, I have eliminated the possibility of anything being wrong with my mappings, because I simply outcommented all fields except a string field and the primary key (which is a GUID). The exception keeps on being thrown nonetheless. Also, the object in question does not contain any child objects.
Instead I suspect there is something wrong with how I invoke my Session, so there is something in the cache of the Session that causes this problem for some nebulous reason.
I use this Util class for managing sessions:
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();
}
}
}
So at the beginning of every operation of my DataObjectManager classes, I get the session from a common method inherited from a superclass that fetches the session like so:
public ISession GetSession()
{
return FcoNHibernateUtil.GetCurrentSession();
}
When all operations in one sweep of the console app (or a unit test) are done, I make sure the DisposeCurrentSession-method is called.
Is there anything that can be improved that may prevent these exceptions from coming?
EDIT
This is the stack trace:
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
And the method where it occurs:
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:
I am getting one clue and that is that this happens when the session is flushed automatically when getting the object. So it looks like the error is happening on the objects that were residing in the session from earlier transactions, but were not yet flushed. So the issue is lurking in the session until it is used again.
The easiest way would be to extract the NHibernate source somewhere, point Visual Studio to it and check which value throws the exception when being casted to DateTime
. Then go up some steps in the call stack to find the object where the value is in. That way you should be able to find the error.
I am resorting to not re-using the Session, but the SessionFactory instead. That helped.
精彩评论