I'm having trouble with some NHibernate Code.Basically I'm trying to keep session lifetime as short as possible to minimize state information in the application.
I find it rather hard to describe my problem without being specific, so I'll just go ahead and use Article and Category metaphors.
public class Article
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public override string ToString() { return "cat-" + this.Id.ToString(); }
}
public class ArticleMapping : ClassMap<Article>
{
public ArticleMapping()
{
this.Id( x => x.Id, "id" ).GeneratedBy.Assigned();
this.Map( x => x.Name, "name" );
this.References( x => x.Category ).Fetch.Join().Cascade.None();
}
}
public class CategoryMapping : ClassMap<Category>
{
public CategoryMapping()
{
this.ReadOnly();
this.Id(x => x.Id, "id").GeneratedBy.Assigned();
this.Map(x => x.Name, "name");
}
}
What I do is create a new Article, give it a name, Assign a Category from a list loaded via the method described below and attempt to save.
I get the following warning:
Unable to determine if cat-1 with assigned identifier is transient or detached
If you take a look at the model and mapping code, you will see that cat-1 should not be persisted at all - it is a Category and defined readonly and non-cascading.
//code that loads the list of categories
IStatelessSession session = this.SessionService.GetStatelessSession();
IList<Category> cats = session.CreateCriteria<Category>().List<Category>();
this.SessionService.EndSession(session);
//code that's called to save the instance
ISession session = this.SessionService.GetSession();
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(article);
transaction.Commit();
}
this.SessionService.EndSession(session);
If I call the Save method again, it all goes banana-shaped:
Exception:
NHibernate.StaleStateException: Unexpected row count: 0; expected: 1
Stacktrace:
at NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched(Int32 rowCount, IDbCommand statement) at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFieldA first chance exception of type 'NHibernate.StaleStateException' occurred in NHibernate.dll s, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session)
at NHibernate.Action.EntityUpdateAction.Execute()
at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
at NHibernate.Engine.ActionQueue.ExecuteActions()
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
I used to think NHibernate was free from black magic, but this makes me wanna visit my voodoo priest to ask for help from the other realm...
Does anyone have any idea where the StaleStateException is coming from? Where did I go wrong this time around?
Thanks in advance
Sebi