CSharped
CSharped

Reputation: 1287

How to make NHibernate repositories Thread safe

I have a NHibernate repository class, which is doing some READ operations on multiple table in a single transaction.

But I have an old piece of code which is trying to call this NHibernate class on Parallel Threads, something like

someList.AsParallel().Select(x=>x.repo.GetData());

And the operation fails saying SQL Doesn't support multiple transactions , How can make the ISession in NHibernate thread safe?

Upvotes: 0

Views: 707

Answers (2)

Frédéric
Frédéric

Reputation: 9864

NHibernate ISession is not thread safe, period.
From NHibernate reference documentation Chapter 1, Getting started section:

An ISession is a non-threadsafe object that represents a single unit-of-work with the database.

You should change your old piece of code instead.

This piece of code looks like a coding horror anyway. It suffers the n+1 loads bad practice. Usually this one occurs with lazy-loading not correctly setup (by forgetting to set adequate batch-size in mappings on entities and collections, while not having set default_batch_fetch_size configuration parameter). But there, it is explicitly coded!

Calling DB in a loop is a performance anti-pattern that you should fix first. Calling it in an AsParallel looks only as a poor attempt from original developer to "optimize" this coding horror.

To fix it, you should load all your data in a single call, then dispatch it on your list as needed. You may first project your data into a dictionary for avoiding an O(n²) dispatching algorithm.

Once done, the AsParallel should have vanished, and your thread safety trouble too.

If the thing is too complex (way more that what your example shows), or really corresponds to something that needs to be done with parallelism, then you should instantiate one dedicated ISession for each GetData in your parallel processing.

Upvotes: 4

Stefan Steinegger
Stefan Steinegger

Reputation: 64628

Note that when using lazy loading and proxies, not even the entities are thread safe!

  • If the queries are to be parallelized, you need to do it in separate transactions. Consider isolation and atomicity. If it needs to be in a single transaction, you need to improve performance in a different way.
  • If calculations on the entities are to be parallelized, you should do optimized queries in the main thread, copy the data in the entities to DTOs and process it in multiple threads. Do not access entities from background threads!

Upvotes: 1

Related Questions