5

I´m receiving a very strange error with NHibernate 2.1.2.4000 GA and latest version of FluentNHibernate. I can save an entity but can´t load it back after a call to Flush() and Clear().

This is my entity:

public class Application
{
 public int Id { get; set; }
 public string Name { get; set; }
 public string KeyName { get; set; }
 public string Description { get; set; }
 public string Url { get; set; }

 public override bool Equals(object obj)
 {
  if (null != obj && obj is Application)
  {
   return ((Application)obj).Id == this.Id;
  }
  else
  {
   return base.Equals(obj);
  }
 }
}

My configuration Map:

public class ApplicationMap : ClassMap
{
 public ApplicationMap()
 {
  Table("[Application]");

  Not.LazyLoad();

  Id(x => x.Id, "ApplicationId")
   .GeneratedBy.Identity();
  Map(x => x.Name, "ApplicationName")
   .Nullable()
   .Length(50);
  Map(x => x.Description, "ApplicationDescription")
   .Nullable()
   .Length(200);
  Map(x => x.KeyName, "ApplicationKeyName")
   .Nullable()
   .Length(50);
  Map(x => x.Url, "ApplicationLink")
   .Nullable()
   .Length(50);
 }
}

How I create my ISession:

var _sessionFactory = Fluently.Configure()
 .Database(
  SQLiteConfiguration.Standard.InMemory()
  .ProxyFactoryFactory(typeof(ProxyFactoryFactory)))
 .Mappings(
  m => m.FluentMappings.AddFromAssemblyOf())
 .ExposeConfiguration(cfg => Config = cfg)
 .BuildSessionFactory(); 

var _session = _sessionFactory.OpenSession();

And this is the code that won´t work:

Application myApp = new Application()
{
 Id = 1,
 Description = "MyApp",
 KeyName = "MyApp",
 Name = "My App",
 Url = "http://www.myapp.com"
};

_session.Save(myApp);
var idMyApp = myApp.Id;
_session.Flush();
_session.Clear();
_session = NHibernateHelper.CreateSession();
var a = _session.Load(idMyApp);

The Exception I get at the moment I try to Load the object back from database is:

Test method HNI.Portal.Test.MappingTests.RoleMap.CanCorrectMapRole threw exception:  NHibernate.ObjectNotFoundException: No row with the given identifier exists[HNI.Portal.Core.Entities.Application#1].

and the StackTrace:

NHibernate.Impl.SessionFactoryImpl.DefaultEntityNotFoundDelegate.HandleEntityNotFound(String entityName, Object id)
NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType)
NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType)
NHibernate.Impl.SessionImpl.Load(String entityName, Object id)
NHibernate.Impl.SessionImpl.Load(Type entityClass, Object id)
NHibernate.Impl.SessionImpl.Load[T](Object id)

I´m not sure if I should call Flush() and Clear() (still doing research on it), but I´m getting this error while writing tests with PersistenceSpecification. This is how PersistenceSpecification does on CheckList() assert to verify if a list is being correctly saved, which is not for me. I stepped into the code and got to this repro.

The application row is correctly inserted in the database but it won´t load again. It happens both with SqlServer and Sqlite.

Hope you guys can help me.

Thanks a lot!

1
  • Did you breakpoint your code to see whether the value of your ID is correct compared to the value identitied by your DBMS? Commented Feb 8, 2010 at 16:07

4 Answers 4

2

You are setting the id but it's an Identity. You should not set it, SQL does that for you.

Instead of creating a new session use the same one, and retrieve using Get instead of Load.

On the difference between Load and Get: http://ayende.com/Blog/archive/2009/04/30/nhibernate-ndash-the-difference-between-get-load-and-querying-by.aspx

Sign up to request clarification or add additional context in comments.

5 Comments

This is odd. It saved the object (like it was doing before), then gave me a "row not found" exception when I tried to Load it. The important point is that I could make my assertion work be doing what you said and adding Cascade to parent of this Application entity. I will do some more testing to make sure everything is working.
+1 about identity id. -1 about session.Clear() since it makes sense to clear session while testing to make sure you hit db and not cache.
pedro, I have .Clear() in my example because PersistenceSpecification.VerifyTheMappings uses it so I needed it to repro the problem.
@Pedro: Creating a new session asserts that the Load() method hits the database. Using the same session, NHibernate could return the cached entity. Anyhow, it is only adviseable to use the same session within one and only context, either a WinForm or a WebPage. After this context is no longer viable, the session should be released in favor of another new one. Using the same session for too long cause memory leaks from the ISession interface as it keeps tracks of the entities manipulated.
@Will: Clear will completely evict all objects from the session cache. It could still be retrieved from the second level cache, if you did set it up, but considering it's a test wouldn't you say that Clear is enough ?
1

I think you're grabbing Id out of myApp too early. Try doing _session.Flush() before looking up Id. Since you're using an Identity Generator, NHibernate bubbles the generated Id back up to your object, but that doesn't happen until the session is flushed (usually at transaction commit-time).

Comments

0

Your using two differen ways to create the session?

NHibernateHelper.CreateSession();

and

_sessionFactory.OpenSession();

maybe you should try _sessionFactory.OpenSession(); to get a session for retrieval.

1 Comment

_sessionFactory is static inside NHibernateHelper so they are using the same Factory to create the session.
0

you don't need to flush manually since the framework will notice that you perform a search on an entity of which there are still pending changes, those changes will be flushed before the get, in this I think that idMyApp will be 1 instead of the right generated id from the database....causing your get code to fail...

1 Comment

He's creating a new session, though, and that new session won't notice those unflushed changes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.