Avoid first level cache for an entity in NHibernate? - nhibernate

I have an entity which is updated externally (using triggers, stored procedures). This means the entity can change without my knowledge in the same session, and it is required for me that I always perform a database hit, and never use the entity from the first level cache.
Is this possible using NHibernate (or actually, Castle ActiveRecord)?

You cold use a IStatelessSession instead of ISession to disable first level cache:
using (ISessionFactory sf = cfg.BuildSessionFactory())
using (IStatelessSession session = sf.OpenStatelessSession())
{
// ...
}

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>

NHibernate ISession.Update

I have noticed, by using log4net, that when calling ISession.Update, it updates all the changed objects.
For example:
// Change 2 instances
user1.IsDeleted = true;
user2.UserName = "Xyz";
// Call session.Update to update the 2 users
using (ITransaction transaction = session.BeginTransaction())
{
Session.Update(user1); // This updates both user1 & user2
transaction.Commit();
}
using (ITransaction transaction = session.BeginTransaction())
{
Session.Update(user2); // Now there is no need for this
transaction.Commit();
}
Is this the default behavior of NHibernate or has something to do with my mapping file?
Can I make NHibernate update one by one?
It's the normal and default behavior:
Hibernate maintains a cache of Objects
that have been inserted, updated or
deleted. It also maintains a cache of
Objects that have been queried from
the database. These Objects are
referred to as persistent Objects as
long as the EntityManager that was
used to fetch them is still active.
What this means is that any changes to
these Objects within the bounds of a
transaction are automatically
persisted when the transaction is
committed. These updates are implicit
within the boundary of the transaction
and you don’t have to explicitly call
any method to persist the values.
From Hibernate Pitfalls part 2:
Q) Do I still have to do Save and
Update inside transactions?
Save() is only needed for objects that
are not persistent (such as new
objects). You can use Update to bring
an object that has been evicted back
into a session.
From NHibernate's automatic (dirty checking) update behaviour:
I've just discovered that if I get an
object from an NHibernate session and
change a property on object,
NHibernate will automatically update
the object on commit without me
calling Session.Update(myObj)!
Answer: You can set Session.FlushMode to
FlushMode.Never. This will make your
operations explicit ie: on tx.Commit() or session.Flush().
Of course this will still update the
database upon commit/flush. If you do
not want this behavior, then call
session.Evict(yourObj) and it will
then become transient and NHibernate
will not issue any db commands for it.
This is the default behavior when FlushMode of session is Auto or Commit.
In these cases calling transaction.Commit() flushes the session & updates ALL persistent objects
So if you remove the calls Session.Update it wouldn't make any difference
Can I make NHibernate update one by one?
Yes. use FlushMode.Never or postpone commiting the session if possible. I guess you don't need to use Evict for this case

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.

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.

NHibernate update on single property updates all properties in sql

I am performing a standard update in NHibernate to a single property. However on commit of the transaction the sql update seems to set all fields I have mapped on the table even though they have not changed. Surely this can't be normal behaviour in Nhibernate? Am I doing something wrong? Thanks
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var singleMeeting = session.Load<Meeting>(10193);
singleMeeting.Subject = "This is a test 2";
transaction.Commit();
}
}
This is the normal behavior. You can try adding dynamic-update="true" to your class definition to override this behavior.
Well. yes this is normal behaviour for NHibernate. You can use generated attribute for your properties to change the behaviour. Details on Ayende's blog.
Why is this default is because with dynamics you don't get your query plan cached. And usually you don't mind that you send few more bytes over high speed network connection between your application server and database. Unless you are saving long strings where this setting is perfectly appropriate.