D
D
Dem0n132014-02-01 15:36:51
.NET
Dem0n13, 2014-02-01 15:36:51

NHibernate: why is ISession not working after GenericADOException?

Class for working with domain entities:

public class Repository<T> : IDisposable
    where T : BaseEntity
{
    private readonly ISession _session; // сессия открыта пока существует репозиторий
    public Repository()
    {
        _session = Db.OpenSession();
    }
    public T Get(int id)
    {
        return Transaction(() => _session.Get<T>(id));
    }
    public IList<T> GetAll()
    {
        return Transaction(() => _session.CreateCriteria<T>().List<T>());
    }
    public int Add(T entity)
    {
        return Transaction(() => (int) _session.Save(entity));
    }
    public void Remove(T entity)
    {
        Transaction(() => _session.Delete(entity));
    }
    public bool Remove(int id)
    {
        var query = string.Format("from {0} where Id = {1}", typeof (T).Name, id);
        return Transaction(() => _session.Delete(query)) == 1;
    }
    private void Transaction(Action command)
    {
        using (var transaction = _session.BeginTransaction())
        {
            command();
            transaction.Commit();
        }
    }
    private TOut Transaction<TOut>(Func<TOut> command)
    {
        using (var transaction = _session.BeginTransaction())
        {
            var result = command();
            transaction.Commit();
            return result;
        }
    }
    public void Dispose()
    {
        _session.Close();
    }
}

There is an entity Entity : BaseEntity, which, in addition to ID, has a unique constraint set on the TIME field.
I am writing a test (NUnit):
[Test]
public void EntityRepository()
{
    using (var repository = new Repository<Entity>())
    {
        var time = DateTime.UtcNow;
        var entity = new Entity(time);
        var badEntity = new Entity(time); // сущность с таким же уникальным полем

        var id = repository.Add(entity);
        Assert.AreNotEqual(default(int), entity.Id); // success (поле ID присвоено)

        var get = repository.Get(id);
        Assert.AreEqual(entity, get); // success (в рамках одной сессии это будет выполняться)

        Assert.Throws<GenericADOException>(() => repository.Add(badEntity)); // success (при добавлении сущности с таким же значением уникального поля выпало исключение)
        
        var isRemoved = repository.Remove(id); // NHibernate.AssertionFailure : null id in ... (больше с сессией работать невозможно)
        Assert.IsTrue(isRemoved);
    }
}

When removing the line Assert.Throws(() => repository.Add(badEntity)); the test is complete.
Why is this happening? What should be my actions after an exception is thrown? Why doesn't ITransaction.Rollback(), which is called implicitly at the end of using, rollback the ISession state?
PS: when debugging the test, I noticed that after executing the line with the exception _session.Statistics.EntityCount == 2, although I expect it to be 1. Is this a NHibernate bug?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question