Can I flush my NHibernate session and get a new session without committing the transaction? - nhibernate

I'm using Castle ActiveRecord for persistence, and I'm trying to write a base class for my persistence tests which will do the following:
Open a transaction for each test case and roll it back at the end of the test case, so that I get a clean DB for each test case without me having to rebuild the schema for each test case.
Provide the ability to flush my NHibernate session and get a new one in the middle of a test, so that I know that my persistence operations have really hit the DB rather than just the NHibernate session.
In order to prove that my base class (ARTestBase) is working, I've come up with the following sample tests.
[TestFixture]
public class ARTestBaseTest : ARTestBase
{
[Test]
public void object_created_in_this_test_should_not_get_committed_to_db()
{
ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"});
Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1));
}
[Test]
public void object_created_in_previous_test_should_not_have_been_committed_to_db()
{
ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"});
Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1));
}
[Test]
public void calling_flush_should_make_nhibernate_retrieve_fresh_objects()
{
var savedEntity = new Entity {Name = "test"};
ActiveRecordMediator<Entity>.Save(savedEntity);
Flush();
// Could use FindOne, but then this test would fail if the transactions aren't being rolled back
foreach (var entity in ActiveRecordMediator<Entity>.FindAll())
{
Assert.That(entity, Is.Not.SameAs(savedEntity));
}
}
}
Here is my best effort at the base class. It correctly implements Flush(), so the third test case passes. However it does not rollback the transactions, so the second test fails.
public class ARTestBase
{
private SessionScope sessionScope;
private TransactionScope transactionScope;
[TestFixtureSetUp]
public void InitialiseAR()
{
ActiveRecordStarter.ResetInitializationFlag();
ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
}
[SetUp]
public virtual void SetUp()
{
transactionScope = new TransactionScope(OnDispose.Rollback);
sessionScope = new SessionScope();
}
[TearDown]
public virtual void TearDown()
{
sessionScope.Dispose();
transactionScope.Dispose();
}
protected void Flush()
{
sessionScope.Dispose();
sessionScope = new SessionScope();
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
SQLiteProvider.ExplicitlyDestroyConnection();
}
}
Note that I'm using a custom SQLite provider with an in-memory database. My custom provider, taken from this blog post, keeps the connection open at all times to maintain the schema. Removing this and using a regular SQL Server database doesn't change the behaviour.
Is there a way to acheive the required behaviour?

Not too sure about ActiveRecord, but in NHibernate a transaction belongs to a session, not the otherway round.
If you've used ADO.Net a lot, this will make more sense, as to create an IDbTransaction you need to use the connection. ActiveRecord's TransactionScope (and NHibnerate's ITransaction) essentially wrap an IDbTransaction, so you need to create the SessionScope before the TransactionScope.
What you might also find (depending on if you're using NHibernate 1.2 GA or NHibernate 2.*, and what FlushMode your SessionScope has) is that your call to FindAll() may cause the session to flush anyway, as NHibernate will realise that it can't retrieve the correct data without actioning the last call to Save.
This all said and done, have you tried using SessionScope.Flush() instead of creating a new SessionScope?

Using SessionScope.Flush() makes my third test fail. As I understand it, Flush() executes the SQL to push my records into the DB, but does not evict objects from the session. That fits with what you say about FindAll() causing a flush.
What I really want is SessionScope.Flush() (to synchronise state of DB with session) plus SessionScope.EvictAll() (to ensure I get fresh objects in subsequent queries). My new SessionScope() was an attempt to simulate EvictAll().
Your comments about the session enclosing the transaction rather than the other way round did give me an idea. I'm not sure how kosher it is to create a new SessionScope inside a TransactionScope inside a flushed SessionScope, and expect it to participate in the transaction, but it seems to work:
public abstract class ARTestBase
{
private SessionScope sessionScope;
private TransactionScope transactionScope;
private bool reverse;
private IList<SessionScope> undisposedScopes;
[TestFixtureSetUp]
public void InitialiseAR()
{
ActiveRecordStarter.ResetInitializationFlag();
ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
InitialiseIoC();
undisposedScopes = new List<SessionScope>();
}
[SetUp]
public virtual void SetUp()
{
sessionScope = new SessionScope();
transactionScope = new TransactionScope(OnDispose.Rollback);
transactionScope.VoteRollBack();
base.CreateInstanceUnderTest();
reverse = false;
}
[TearDown]
public virtual void TearDown()
{
if (reverse)
{
sessionScope.Dispose();
transactionScope.Dispose();
}
else
{
transactionScope.Dispose();
sessionScope.Dispose();
}
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
foreach (var scope in undisposedScopes)
{
scope.Dispose();
}
SQLiteProvider.ExplicitlyDestroyConnection();
}
protected void Flush()
{
reverse = true;
sessionScope.Flush();
undisposedScopes.Add(sessionScope);
sessionScope = new SessionScope();
}
}
On further thought, this won't allow you to flush more than once in each test case. I think I can handle that by tracking the scopes more carefully. I might look into it later.

Related

How to make Nhibernate not to persist the changes in object to the database

There is a collection of data in the database on which a integration test is run. For preventing NHibernate persisting objects modification in the database an EventListener that inherits from DefaultSaveOrUpdateEventListener was implemented.
Then there is a method:
public override void OnSaveOrUpdate(SaveOrUpdateEvent #event)
{
#event.Session.CancelQuery();
Trace.TraceWarning("NhibernateSaveUpdateCanceler: Persistence will be ignored.");
}
Unfortunately this does not work as expected. So intended behavior is to catch the moment when changes are written in the database and cancel it somehow though leaving objects as there are so modification on them can be validated.
Thanks.
EDIT
Cannot do this because there are multiple transaction in the tested method so there is contradiction in requirements by persisting changes so that there are available for all transaction from one side and that changes are not persistent in the database from the other.
The SaveOrUpdate event listener is called when session.Save or session.Update is called. When changes are flushed, the FlushEntity event is called for each entity. Implement IFlushEntityEventListener.
re-write your integration test with an Integration test fixture base. in the base class create:
a fixture setup that initializes nhibernate and creates a session factory
a fixture teardown that closes the session factory
a test setup that creates a session and transaction
a test teardown that rolls back the transaction and closes the session.
like this
[TestFixture]
public abstract class TestFixtureBase
{
protected ISessionFactory SessionFactory { get; private set; }
protected ISession Session { get; private set; }
protected ITransaction Tx { get; private set; }
[TestFixtureSetUp]
public virtual void SetUp()
{
var nh = new NHInit();
nh.Initialize();
SessionFactory = nh.SessionFactory;
}
[TestFixtureTearDown]
public virtual void TearDown()
{
SessionFactory.Close();
}
[SetUp]
public void Test_Set_Up()
{
Session = SessionFactory.OpenSession();
Tx = Session.BeginTransaction();
}
[TearDown]
public void Test_tear_down()
{
Tx.Rollback();
Tx.Dispose();
Session.Close();
}
}
then write your test.

Unit of Work Questions - Nhibernate (Isolation Level & What else would be in a UoW)

I am looking into the UoW pattern and have 3 questions.
public class UnitofWork : unitofwork.Models.IUnitofWork
{
private readonly ITransaction transaction;
private readonly ISession session;
public UnitofWork(ISession session)
{
this.session = session;
session.FlushMode = FlushMode.Auto;
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don't have an active transaction");
}
transaction.Commit();
}
public void Rollback()
{
if (transaction.IsActive)
{
transaction.Rollback();
}
}
public void Dispose()
{
if (session.IsOpen)
{
session.Close();
}
}
}
I just learning about "IsolationLevels" and I am wondering which one should you be using? What happens if you need to make use of multiple "IsolationLevels" for different transactions? How would you configure your UoW(would you make multiple implementations of the above class?)
Other then Rollback and Commit was usually goes into the UoW? I know stuff like creating,updating,getting queries would go into a repository(if your using this pattern) So what else would you typicall see in it?
I copied this UoW from some site(don't have it on hand right now) and made changes it to fit my needs(for instance I am using ninject so I felt there was no point in the UoW taking in the sessionFactory and opening a session in the UoW)
I am wondering what is the Dispose for? I seen this a few times before(some seem to implement IDispose).
I don't actually use it right now in any of my code. I am wondering if it is necessary for me as I mentioned I am using ninject and that handles the session(ie closes it once I am done)
public void Dispose()
{
if (session.IsOpen)
{
session.Close();
}
}
Edit
I added this to my unit of work
public void BeginTransaction()
{
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void BeginTransaction(IsolationLevel level)
{
transaction = session.BeginTransaction(level);
}
I removed it from the constructor
The ISession itself is a unit-of-work implementation, so implementing your own is entirely optional.
IsolationLevel is declared in the System.Data namespace. ReadCommitted is the most commonly used; this is also the default for SQL Server. I tried using Chaos once just because I like the name but SQL Server doesn't support it.
The code you have in the question creates a transaction as soon as the session is opened, so it's a transaction per UOW implementation; note that if you call Commit or Rollback, any additional operations will occur outside of transaction scope. I really dislike this and prefer to control my own transaction scope, so I would have a BeginTransaction in my UOW.
Classes that implement IDisposable must implement the Dispose method and should be used in a using block or disposed of manually. It means that the class has clean up operations that need to run, such as closing the ISession. Here, the Dispose method should just call ISession.Dispose instead of just closing the session.

Where should the transaction boundary be in a repository pattern?

I have a repository like so:
public interface IRepository
{
void Save<T>(T entity);
void Create<T>(T entity);
void Update<T>(T entity);
void Delete<T>(T entity);
IQueryable<T> GetAll<T>();
}
My question is, where should my transaction boundaries be? Should I open a new transaction on every method and commit it before returning? Or should it be around the entire repository so that the transaction is only committed when the repository is disposed/garbage collected?
Transactions should not be applied to repositories, because if more than one needs to participate in a transaction there's no way to say it.
Have a separate service tier that uses repositories and model objects to satisfy use cases. The service methods know where the transaction boundaries need to be. That's where they should be applied.
Unit of Work is definitely the way to go. If you're using SQL Server with a local database, TransactionScope will do most of the heavy lifting for you; as long as you share sessions between repositories (which you're doing through constructor injection, right...?), then you can nest these to your heart's content. By default, it enlists in the "ambient" transaction if there is one, and starts a new one if there isn't, which is exactly the behaviour you want for a unit of work.
So your repositories might look like this:
public class UserRepository : IUserRepository
{
public UserRepository(ISession session)
{
this.Session = session;
}
public void Save(User user)
{
using (TransactionScope tsc = new TransactionScope())
{
Session.Save(user);
tsc.Complete();
}
}
protected ISession Session { get; set; }
}
public class OrderRepository : IOrderRepository
{
public OrderRepository(ISession session)
{
this.Session = session;
}
public void Save(Order order)
{
using (TransactionScope tsc = new TransactionScope())
{
Session.Save(order);
tsc.Complete();
}
}
protected ISession Session { get; set; }
}
Then you can perform the complete unit of work like so:
User currentUser = GetCurrentUser();
using (TransactionScope tsc = new TransactionScope())
{
ISession session = SessionFactory.OpenSession();
Order order = new Order(...);
order.User = currentUser;
IOrderRepository orderRepository = GetOrderRepository(session);
orderRepository.Save(order);
currentUser.LastOrderDate = DateTime.Now;
IUserRepository userRepository = GetUserRepository(session);
userRepository.Save(currentUser);
tsc.Complete();
}
If you don't like TransactionScope or your environment prevents you from using it effectively then you can always implement your own UOW or use an existing implementation. Or if you're just an architectural neat-freak then you can do both - use a generic unit-of-work interface with one of the main DI libraries, and implement your concrete UOW using the TransactionScope.
One of the options is the unit of work pattern. This is already explained in several previous questions.

Creating an Update method in my nHibernate repository

My current repository looks like:
public class Repository<T> : IRepository<T>
{
public ISession Session
{
get
{
return SessionProvider.GetSession();
}
}
public T GetById(int id)
{
return Session.Get<T>(id);
}
public ICollection<T> FindAll()
{
return Session.CreateCriteria(typeof(T)).List<T>();
}
public void Add(T t)
{
Session.Save(t);
}
public void Remove(T t)
{
Session.Delete(t);
}
}
the interface:
public interface IRepository<T>
{
T GetById(int id);
ICollection<T> FindAll();
void Add(T entity);
void Remove(T entity);
}
How would I create an update method?
Do I have to call flush or transaciton commit to write to the database?
I have tried updating an object, and calling saveorupdate(); but it didn't change the value in the db.
You don't.
The repository pattern means: "emulate a normal collection for persistence usage"
With normal collection, I mean something like List<T>
When you do this:
var list = new List<User>();
list.Add(myUser);
myUser.MyProperty = newValue;
MyProperty for the user in both the list and the myUser variable are set to newValue, because it's the same reference. It would be rather strange to do this instead:
var list = new List<User>();
list.Add(myUser);
myUser.MyProperty = newValue;
list.Update(myUser);
Repository should behave the same as other collections, like list. When you need an explicit update, please do not call it a repository. Collections do not work like that.
To answer your question: Yes you have to commit a transaction or flush the session to change persist the changes in the session in the database. It might be better to make a unit of work responsible for this, instead of the repository, and inject the unit of work into the repository, instead of the session.
We don't actually have an Add method on our repositories. Instead we just have a Save method (not in love with the name). The method does a Session.SaveOrUpdate() which works fine since we have unsaved-value specified on our definitions.
In terms of seeing actual changes to the database this doesn't occur until you close your session. This saves NHibernate from doing any work until it absolutely has to.
The only reason you would ever need to flush is if you wanted to get an id back from your database but it's for this reason that identity isn't preferred NHibernate Avoid Identity Generator When Possible

How to properly use a NHibernate ISession object - Session Is Closed! errors

I'm running into issues with my ISessions in NHibernate. I keep getting "Session Closed!" errors. Can some one please show me the correct pattern including a definition of the following methods and when to use each:
ISession.Close()
ISession.Dispose()
ISession.Disconnect()
Here's my problem. I have a callback setup to fire off a process that awards badges to players every couple of minutes. However I keep getting "Session Closed!" errors or errors about not being able to associate collections.
Here's my Repository:
public class NHibernateRepository : IRepository
{
#region Fields
private ISession _session;
private readonly ISessionFactory _sessionFactory;
#endregion
#region Constructors
public NHibernateRepository(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
#endregion
#region IRepository Implementation
public ISession OpenSession()
{
_session = _sessionFactory.OpenSession();
return _session;
}
public IQueryable<TModel> All<TModel>()
{
return _session.Linq<TModel>();
}
public void Save<TModel>(TModel model)
{
_session.Save(model);
}
public void Update<TModel>(TModel model)
{
_session.Update(model);
}
public void Delete<TModel>(TModel model)
{
_session.Delete(model);
}
public ITransaction BeginTransaction()
{
return _session.BeginTransaction();
}
public void Flush()
{
_session.Flush();
}
#endregion
}
Here's my usage. The repository is getting injected via Structure Map
private Object _awardBadgesLock = new object(); //In case the callback happens again before the previous one completes
public void AwardBadges()
{
lock (_awardBadgesLock)
{
using(session = _repository.OpenSession())
{
foreach (var user in _repository.All<User>().ToList())
{
var userPuzzles = _repository.All<Puzzle>().ByUser(user.Id).ToList();
var userVotes = _repository.All<Vote>().Where(x => x.UserId == user.Id).ToList();
var userSolutions = _repository.All<Solution>().ByUser(user.Id).ToList().Where(x => !userPuzzles.Select(y => y.Id).Contains(x.PuzzleId));
var ledPuzzles = GetPuzzlesLedByUser(user.Id);
AwardPlayerBadge(user, userSolutions);
AwardCriticBadge(user, userVotes);
AwardCreatorBadge(user, userPuzzles);
AwardRidlerBadge(user, userPuzzles);
AwardSupporterBadge(user, userVotes);
AwardPopularBadge(user, userPuzzles);
AwardNotableBadge(user, userPuzzles);
AwardFamousBadge(user, userPuzzles);
AwardLeaderBadge(user, ledPuzzles);
using (var tx = _repository.BeginTransaction())
{
_repository.Update(user);
tx.Commit();
}
}
}
}
}
You should always use session.Dispose();
The other are for very strange occurances
I advice you to read the documentation of ISession on
https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs
Anyway the proper way to clean up when you are finished with the session is to dispose it (or better, surround the usage with using statement). In this case, "using" closes the session and suppresses the finalizer, i.e. it prevents the session object from unnecessarily surviving the next garbage collecting and saves the memory.
If the connection is already closed, disposing it will not throw an exception. On the other hand, closing after disposing (or after closing) throws an exception.
The documentation recommends calling disconnect instead of closing, because this releases the connection to the connection pool. You should call Reconnect before using a disconnected session.
For my needs, I always use "using" which calls Dispose and have never used the othe two functions.
The issue lies in the fact the ISession is not thread-safe. There were multiple methods being fired on separate threads that all created an instance of ISession. The issue was really with the fact that they all shared the same SessionFactory. Image both of these methods are fired off on separate threads:
ISessionFactory _sessionFactory;
void MethodOne()
{
using(ISession session = _sessionFactory.OpenSession())
{
//Do something with really quick with the session
//Then dispose of it
}
}
void MethodTwo()
{
//OpenSession() actually returns the same instance used in the
//previous method that has already disposed of the object;
using(ISession session = _sessionFactory.OpenSession())
{
//Do something with a session that has already been disposed
//throws errors
}
}
How I fixed it was basically ditching NHIbernate in these scenarios and called stored procs instead. I think it turned out to be more performant in my situation anyway.
About the problem, your method of locking is right as long as you dispose the session but probably the bug lies under another part of your codes. by the way about the design, it is better that you pass the session variable to repositories because of unit of work implementation of the session and aggregate root's transaction like this:
using (ISession session = SessionFactory.OpenSession())
{
Repository1 rep1 = new Repository1(session);
Repository2 rep1 = new Repository2(session);
Repository3 rep1 = new Repository3(session);
// some logics
using (var tx = session.BeginTransaction())
tx.Commit();
}
.
.
.