From the trunk.
In AbstractSaveEventListener.PerformSaveOrReplicate
source.PersistenceContext.AddEntry(...) is called before OnSave
source.PersistenceContext.AddEntity(...) is called after OnSave
If an interceptor throws for an association, AddEntity is never called for that association
So if you call Session.Evict on the root of that object a KeyNotFoundException is thrown (for GUID Id's, a different one for others)
Because In DefaultEvictEventListener:
if the object is NOT an INHibernateProxy, it removes the entry, then the entity without checking whether there is an entity to remove. Thus in my situation it throws an exception.
Attached a test to drop into the Nhibernate.Tests project
Code:
using System;
using System.Collections;
using NHibernate.Test.Cascade;
using NHibernate.Type;
using NUnit.Framework;
namespace NHibernate.Test.Interceptor
{
[TestFixture]
public class EvictProblemFixture : TestCase
{
protected override string MappingsAssembly
{
get { return "NHibernate.Test"; }
}
protected override IList Mappings
{
get { return new[] { "Cascade.Job.hbm.xml", "Cascade.JobBatch.hbm.xml" }; }
}
[Test]
public void EvictWorksAfterOnSaveError()
{
ISession s = OpenSession(new ThrowingInterceptor());
ITransaction txn = s.BeginTransaction();
JobBatch batch = new JobBatch(DateTime.Now);
batch.CreateJob().ProcessingInstructions = "Just do it!";
batch.CreateJob().ProcessingInstructions = "Throw";
try
{
s.SaveOrUpdate(batch);
}
catch(Exception)
{
s.Evict(batch);
}
finally
{
txn.Rollback();
s.Close();
}
}
public class ThrowingInterceptor : EmptyInterceptor
{
public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
if(entity is Job && ((Job)entity).ProcessingInstructions == "Throw")
throw new Exception();
return base.OnSave(entity, id, state, propertyNames, types);
}
}
}
}
[/quote]