If you are using naitive identities, are objects persistant instantly? - nhibernate

In my asp.net application, I open and close/flush the session at the beginning/ending of each request.
With this setup, I thought it would result in things like:
Entity e = EntityDao.GetById(1);
e.Property1 = "blah";
EntityDao.MakePersistant(e);
e = EntityDao.GetById(1);
e.Property1 // this won't be blah, it will be the old value since the request hasn't flushed
But I noticed that the value returned was the most recent updated value.
Someone responded that because of they way I have my identity setup?
Can someone explain this behaviour? So I don't need to call flush to ensure it is persisted to the db?

I belive (but could be mistaken) that nHibernate's caching and change-tracking is the reasons for this.
Since this Session instance is still active, nHibernate is tracking the changes you made to 'e'. When you ask for it again it includes those changes in the object returned. What happened when you called MakePersistant (which I assume calls Session.SaveOrUpdate(e)) is that it told that Session instance you are going to save those changes, thus it knows about them and will still show them when you call Session.Get(id) again.
If you instead started another Session and then called Session.Get(id) you wouldn't see those changes if you had not called Flush (or closed the Transaction, since you should be using a Transaction here) as it knows nothing of the changes made in the other Session.
To answer your other question, yes you still need to call Flush or close a Transaction to ensure changes are written to the database. One thing that is neat, is that you don't actually need to call SaveOrUpdate(e). For example this code will cause an Update to the database:
using (var session = SessionFactory.OpenSession())
using (var trans = session.BeginTransaction()){
var e = session.Get(id);
e.Name = "New Name";
trans.Commit();
}
nHibernate knows to update 'e' since it was tracking the changes that were made to during that Session. When I commit that transaction they are written. Note, this is the default behavior and I believe it can be changed if you want to require that .SaveOrUpdate() is called.

Related

Session Flush not Showing SQL when persisting unsaved entities

The scenario is a (more complex) version of the following:
IList<T> ts = Session.QueryOvery<T>().List();
// modify data of multiple objects
ts[0].Foo = "foo0";
ts[1].Foo = "foo1";
using (ITransaction trx = Session.BeginTransaction())
{
// save only one object
Session.Save (ts[0]);
trx.Commit();
}
As NH goes, this will also save ts[1] by default, to prevent stale state (side note : we love control over our SQL, so we turn that off by setting Session.FlushMode=FlushMode.Never).
What really vexes me is the fact that, even though Show_SQL is activated, no sql is shown for the ts[1] updates that are definitely sent to the Database by the flush.
Is there any way I can get those to show up?
As stated in https://stackoverflow.com/a/9403516/1236044 , you just need to add adonet.batch_size setting with value 0 to your config :
<property name="adonet.batch_size">0</property>

Deletion on succes (Active record, Rails)

I'm developing a Rails application that has a background process that updates some user information. In order to do so, this method has to delete all the existing information (stored in another table) and get new information from the Internet. The problem is that if something goes wrong in the midtime users don't have information until the process runs again.
there is something to do like:
transaction = EntityUser.delete_all(:user_id => #current_user.id)
#instructions that adds new entity
...
...
transaction.commit
can anyone suggest something that i can do to avoid this kind of problem?
thank you
Read about ActiveRecord::Transactions. You can wrap everything in a block
ActiveRecord::Base.transaction do
EntityUser.delete_all(:user_id => #current_user.id)
# ...
end
If something goes wrong, you can call raise ActiveRecord::Rollback within that block to cause all changes to the database within the transaction block to be reverted.
Another thought is to soft-delete the EntityUser instance(s) for a User instead of actually removing them from the database. There are gems to help you with this functionality such as acts_as_paranoid.
You would
soft-delete the EntityUser instance(s)
Fetch and build the new EntityUser instance(s)
(Optionally) flush the soft-deleted instance(s) from the database if everything went well
If something goes wrong using this method it's easy to just un-delete the soft-deleted records.

NHibernate FlushMode: How do I set up NHibernate for automatically updating an entity

After I retrieve an entity, I change a property of it.
Then I retrieve the same entity.
How do I say Nhibernate, that it shall update the entity before it loads the entity?
Here the code:
EmployeeRepository employeeRepository = new EmployeeRepository();
Employee employee = employeeRepository.GetById(4);
employee.LastName = "TEST!!!";
Employee employee2 = employeeRepository.GetById(4);
Currently Nhibernate don't make an update in my program. I thought just setting the FlushMode to Auto will update the entity automatically.
EDIT
The background is that I try to reprdouce this behaviour in another application.
There is NO save method! Just this code. The NHibernate version is really old, it is version 1.2.1.4000. maybe there is the catch.
When I set the FlushMode in the brownfield application to Commit then no update statement is generated.
But in my own project I still can not reproduce this "automatic" behaviour.
Are both calls to the employeeRepository ultimately using the same NHibernate ISession instance? If so, then they will return the same object, and the updated LastName value will be reflected. If not, then you will need to make sure you are disposing your ISession instance each time to take advantage of auto flushing.
According to the documentation for the default FlushMode of Auto:
The ISession is sometimes flushed
before query execution in order to
ensure that queries never return stale
state. This is the default flush mode.
So you have to manually flush the session to ensure that your changes are persisted before reading the object again.
EmployeeRepository employeeRepository = new EmployeeRepository();
Employee employee = employeeRepository.GetById(4);
employee.LastName = "TEST!!!";
session.Flush();
Employee employee2 = employeeRepository.GetById(4);
If your repository is using the same ISession for both calls (as it should imo) then employee 4 will be retrieved from the cache and have the change. However, the change will not have been persisted to the database yet.
If your repository GetById methods uses a new session for each call then it will always hit the database to retrieve the employee. If you're disposing of the session in the method then your objects are returned as detached from a session. This strategy defeats the purpose of NHibernate and relegates it to a simple data access tool.

NHibernate - dirty ISession not updating

When the save button is clicked, the following code is run [PersistenceSession is a property returning an ISession instance]:
_storedWill = PersistenceSession.Load<StoredWill>(_storedWillId);
_storedWill.WillReference = txtWillReference.Text;
_storedWill.IntroducerReference = txtIntroducerReference.Text;
//A stack of other properties of the _storedWill object assigned
PersistenceSession.SaveOrUpdate(_storedWill);
A breakpoint set on the final line reveals that PersistenceSession.IsDirty() is true.
However, no update SQL is generated. Can anyone think why?
Thanks
David
You need to Flush the session to have the updates sent to the database. SaveOrUpdate will not send anything to the database unless you are persisting a newly-created entity, whose ID values are database generated. Since you are just updating, all this does is ensures that the _storedWill entity is associated with the ISession returned by the PersistenceSession property.

Flushing in NHibernate

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.