My ISession object's FlushMode is FlushMode.Commit.
I use the unit of work and repository pattern as defined here:
http://nhforge.org/wikis/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.aspx
I recall seeing some examples where some people call a Get() immediately followed by a Flush or a transaction commit. We're they just off their rocker, or is there a reason to do this?
From my test:
[TestMethod]
public void TestMethod1()
{
Employee e;
IRepository<Employee> empRepo;
using(UnitOfWork.Start(Enums.Databases.MyDatabase))
{
empRepo = new Repository<Employee>();
e = empRepo.GetByID(21);
}
Debug.WriteLine(e.UserName);
}
My GetByID repository function just calls Session.Get(id) and I can view the username in the output window (after the session is killed)... so whats the point of any sort of Flush or transaction commit after a Get() ? I would understand if there was a save in there somewhere.
NHibernate assumes that all database operations are done within transactions, so people use them explicitly instead of having NHibernate the RDBMS use them implicitly.
Ayende explains this in more detail in his post NH Prof Alerts: Use of implicit transactions is discouraged.
Edit: Learned something new today. It's not NHibernate using implicit transactions but the DB.
Related
I'm relatively new to NHibernate and I've got a question about it.
I use this code snippet in my MVC project in Controller's method:
MyClass entity = new MyClass
{
Foo = "bar"
};
_myRepository.Save(entity);
....
entity.Foo = "bar2";
_myRepository.Save(entity);
The first time entity saved in database succesfully. But the second time not a single request doesnt go to database. My method save in repository just does:
public void Save(T entity)
{
_session.SaveOrUpdate(entity);
}
What should I do to be able to save and then update this entity during one request? If I add _session.Flush(); after saving entity to database it works, but I'm not sure, if it's the right thing to do.
Thanks
This is the expected behavior.
Changes are only saved on Flush
Flush may be called explicitly or implicitly (see 9.6. Flush)
When using an identity generator (not recommended), inserts are sent immediately, because that's the only way to return the ID.
you should be using transactions.
a couple of good sources: here and here.
also, summer of nHibernate is how I first started with nHibernate. it's a very good resource for learning the basics.
In NHibernate 3.0, FlushMode.Auto does not work when running under an ambient transaction only (that is, without starting an NHibernate transaction). Should it?
using (TransactionScope scope = new TransactionScope())
{
ISession session = sessionFactory.OpenSession();
MappedEntity entity = new MappedEntity() { Name = "Entity", Value = 20 };
session.Save(entity);
entity.Value = 30;
session.SaveOrUpdate(entity);
// This returns one entity, when it should return none
var list = session.
CreateQuery("from MappedEntity where Value = 20").
List<MappedEntity>();
}
(Example shamelessly stolen from this related question)
In the NHibernate source I can see that's it's checking whether there's a transaction in progress (in SessionImpl.AutoFlushIfRequired), but the relevant method ( SessionImpl.TransactionInProgress) does not consider ambient transactions - unlike its cousin ConnectionManager.IsInActiveTransaction, which does consider ambient transactions.
Good news. Thanks to Jeff Sternal (who nicely identified the problem) I updated https://nhibernate.jira.com/browse/NH-3583 and thanks to the NH staff, there's already a fix and a pull request so in the upcoming release 4.1.x.x this ISSUE will be fixed.
You should use an explicit NHibernate transaction always.
using (TransactionScope scope = new TransactionScope())
using (ISession session = sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
//Do work here
transaction.Commit();
scope.Complete();
}
I see you also wrote in the NH dev list - while this can change in the future, that's how it works now.
The answer provided by Diego does not work in the case where you have an oracle database.
(releated question). The session.BeginTransaction will fail because the connection is already part of a transaction.
Looks like we have to write some code around this problem in our application (WCF,NHibernate, Oracle), but it just feels like something that NHibernate should provide out of the box.
So if anyone has a good answer, it would be really appreciated.
For me, I don't know the reason behind, but by forcing session flush before session is disposed seemed to worked for me. e.g.
using(session)
{
//do your work
session.Flush();
}
I verified that this works with my distributed transaction, since without doing this, I always get "transaction has aborted" when TransactionScope is disposed.
Even set session.FlushMode to Commit did NOT work for me.
In the TestFixtureTearDown-part of an NUnit test I try to delete some test-entities created in the TestFixtureSetUp-part. I use the following code
sessionFactory = NHibernateHelper.CreateSessionFactory(cssc["DefaultTestConnectionString"].ConnectionString);
uow = new NHibernateUnitOfWork(sessionFactory);
var g = reposGebruiker.GetByName(gebruiker.GebruikerNaam);
reposGebruiker.Delete(g);
var k = reposKlant.GetByName(klant.Naam);
reposKlant.Delete(k);
// Commit changes to persistant storage
uow.Commit();
However, after the commit, the two entities were still in the database. After searching on I came across this page on SO and so I added:
uow.Session.Flush();
However, still the entities remain in the DB. Does anyone have an idea as to why this is?
I've never used the UoW class you're using, but my projects are implemented using ISession.BeginTransaction and ISession.Transaction.Commit in a helper like this:
public void CreateContext(Action logic)
{
ISession.BeginTransaction();
logic();
ISession.Transaction.Commit();
}
And then:
CreateContext(() =>
Session.Delete(someObject));
This should work.
I want to mention that this is an example, and you'd want to make some abstractions.
How are the repositories created? In for the delete to succeed, the objects must be loaded in the same UoW (ISession) in which the Delete command is issued. The Delete method makes the objects non-persistent and marks them for deletion.
I have a suite of integration tests that run inside transactions.
Sometimes it seems that NHibernate transactions are not being correctly rolled back. I can't work out what causes this.
Here is a slightly simplified overview of the base class that these integration test fixtures run with:
public class IntegrationTestFixture
{
private TransactionScope _transactionScope;
private ConnectionScope _connectionScope;
[TestFixtureSetUp]
public virtual void TestFixtureSetUp()
{
var session = NHibernateSessionManager.SessionFactory.OpenSession();
CallSessionContext.Bind(session);
_connectionScope = new ConnectionScope();
_transactionScope = new TransactionScope();
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
_transactionScope.Dispose();
_connectionScope.Dispose();
var session = CurrentSessionContext.Unbind(SessionFactory);
session.Close();
session.Dispose();
}
}
A call to the TransactionScope's commit method is never made, therefore how is it possible that data still ends up in the database?
Update I never really got my head around the way NHibernate treats transactions but I found that calling Session.Flush() within a transaction would sometimes result in the data remaining in the database, even if the transaction is then rolled back. I am not sure why you can't call Flush, but then roll back. This is a pity because during integration testing you want to be able to hit the database and flush is the only way to do this sometimes.
I had an issue with using the Identity generator that sounds similar. In a nutshell, when saving an object using an identity generator, it has to write to the database in order to get the identity value and can do this outside a transaction.
Ayende has a blog post about this.
This question is a bit of a dupe, but I still don't understand the best way to handle flushing.
I am migrating an existing code base, which contains a lot of code like the following:
private void btnSave_Click()
{
SaveForm();
ReloadList();
}
private void SaveForm()
{
var foo = FooRepository.Get(_editingFooId);
foo.Name = txtName.Text;
FooRepository.Save(foo);
}
private void ReloadList()
{
fooRepeater.DataSource = FooRepository.LoadAll();
fooRepeater.DataBind();
}
Now that I am changing the FooRepository to Nhibernate, what should I use for the FooRepository.Save method? Should the FooRepository always flush the session when the entity is saved?
I'm not sure if I understand your question, but here is what I think:
Think in "putting objects to the session" instead of "getting and storing data". NH will store all new and changed objects in the session without any special call to it.
Consider this scenarios:
Data change:
Get data from the database with any query. The entities are now in the NH session
Change entities by just changing property values
Commit the transaction. Changes are flushed and stored to the database.
Create a new object:
Call a constructor to create a new object
Store it to the database by calling "Save". It is in the session now.
You still can change the object after Save
Commit the changes. The latest state will be stored to the database.
If you work with detached entities, you also need Update or SaveOrUpdate to put detached entities to the session.
Of course you can configure NH to behave differently. But it works best if you follow this default behaviour.
It doesn't matter whether or not you explicitly flush the session between modifying a Foo entity and loading all Foos from the repository. NHibernate is smart enough to auto-flush itself if you have made changes in the session that may affect the results of the query you are trying to run.
Ideally I try to use one session per "unit of work". This means one cohesive piece of work which may involve several smaller steps. If you feel that you do not have a seam in your architecture where you can achieve this, then managing the session inside the repository will also work. Just be aware that you are missing out on some of the power that NHibernate provides you.
I'd vote up Stefan Moser's answer if I could - I'm still getting to grips with Nh myself but I think it's nice to be able to write code like this:
private void SaveForm()
{
using (var unitofwork = UnitOfWork.Start())
{
var foo = FooRepository.Get(_editingFooId);
var bar = BarRepository.Get(_barId);
foo.Name = txtName.Text;
bar.SomeOtherProperty = txtBlah.Text;
FooRepository.Save(foo);
BarRepository.Save(bar);
UnitOfWork.CommitChanges();
}
}
so this way either the whole action succeeds or it fails and rolls back, keeping flushing/transaction management outside of the Repositories.