Injecting custom IDbCommand in NHibernate - fluent-nhibernate

We use Fluent NHibernate with SQL server 2008. I need NHibernate to use my custom DbCommand class (inherited from IDbCommand). In this custom DbCommand class, I want to handle transient errors (e.g. any transient network errors etc...) and retry the same command certain number of times before failing.
I know, Microsoft provides Transient Fault handling block (with methods like SqlConnectionExtensions.OpenWithRetry and similar method for retriable ExecuteNonQuery) for handling transient errors but, I guess it is specific to Windows Azure platform.
Let me know if NHibernate provides any mechanism for injecting custom behaviours.

Related

Problems using EF tools due to application attempting database access

I have an ASP.NET Core 2.2 app using EF Core 2.2.
I have some background worker threads which I start in ConfigureServices(). These threads depend on the DbContext and on other services which I register in ConfigureServices().
I found that when I try to use Add-Migration, the EF tools cause these threads to run, which in turn throw exceptions in the Add-Migration output because the threads try to access a database object that does not yet exist.
It appears the migration is created successfully, however, it makes using the tooling difficult because it appears to fail (exceptions in output, process does not exit, etc).
Some options I see to avoid this:-
a) Somehow detect in ConfigureServices() that the database does/does not match the context (i.e. is "up to date") and act accordingly.
b) Start my worker threads somewhere else that will not get invoked when my app is run by the EF tools. Keeping in mind that starting these threads require a ServiceProvider with the same scope I'm building in ConfigureServices().
c) Detect in my app that I'm being called by the EF tools and avoid launching the worker threads.
I'd appreciate any advice on the most appropriate strategy and the best method of achieving it.
EF Core tools use different strategies for creating derived DbContext, explained in the Design-time DbContext Creation section of the documentation.
Looks like currently you are using From application services. But according to the problem explanation, the most appropriate in your case seems to be From a design-time factory:
You can also tell the tools how to create your DbContext by implementing the IDesignTimeDbContextFactory<TContext> interface: If a class implementing this interface is found in either the same project as the derived DbContext or in the application's startup project, the tools bypass the other ways of creating the DbContext and use the design-time factory instead.

Is there a way to access the current Nhibernate session from anywhere?

I have some legacy code that used to open its own Sqlconnection. And I would now like to use the SqlConnection Nhibernate creates.
But I'd rather avoid to change the code a lot (DI, adding loads of settings, ...), so, Is there a simple (convienent) way to get the current Nhibernate session?
No. What is current NHibernate session anyway?
In a web application, each http request must work with its specific NHibernate session(s).
In a desktop application, each screen will probably use one session for each of their actions.
The NHibernate session is not supposed to be used as a singleton.
You should probably use your session factory to open a new NHibernate session in your legacy code then use its CreateSQLQuery method. Your session factory should usually have a singleton lifetime.
If you bound your NHibernate sessions to some context meaningful for your application (such as the HttpContext, CallContext), you may instead get it from there. Beware of cases which may cause contexts losses (async/await configured for not restoring context, asp.net thread agility (do not cause HttpContext losses but CallContext losses), ...).

Nhibernate with TransactionScope Error - DTC transaction prepre phase failed -- Upgrade to Nhibernate 3.0

I am getting the following exception when using Nhibernate and ADO.Net operations inside the transaction Scope.Eg. It was fine with Nhibernate 2.1 but now upgraded to 3.0 which throws error.
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
GetmemberId(); --> NHibernate Call
Update(); ADO Call OracleDB
}
Since this acts as ambient transaction, Nhibernate tries to dispose the transaction soon before the outer transaction completes.correct me if I am wrong, Is there any solution because help me , But When I move the Nhibernate call outside TransactionScope everything works fine. The example I have given is sample one, mines involves a more complex one, since I have keep both the calls inside TransactionScope and the error Iam getting is as following,
ERROR 13 NHibernate.Impl.AbstractSessionImpl - DTC transaction prepre
phase failed System.ObjectDisposedException: Cannot access a disposed
object. Object name: 'Transaction'. at
System.Transactions.Transaction.DependentClone(DependentCloneOption
cloneOption) at
System.Transactions.TransactionScope.SetCurrent(Transaction
newCurrent) at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction
transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified)
at System.Transactions.TransactionScope..ctor(Transaction
transactionToUse) at
NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment
preparingEnlistment) 2011-02-08 13:41:46,033 ERROR 13
NHibernate.Impl.AbstractSessionImpl - DTC transaction prepre phase
failed System.ObjectDisposedException: Cannot access a disposed
object. Object name: 'Transaction'. at
System.Transactions.Transaction.DependentClone(DependentCloneOption
cloneOption) at
System.Transactions.TransactionScope.SetCurrent(Transaction
newCurrent) at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction
transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified)
at System.Transactions.TransactionScope..ctor(Transaction
transactionToUse) at
NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment
preparingEnlistment)
Try
Configuration.SetProperty(Environment.TransactionStrategy,"NHibernate.Transaction.AdoNetTransactionFactory")
Or in nhibernate config
<property name="transaction.factory_class">
NHibernate.Transaction.AdoNetTransactionFactory
</property>
It worked for me =)
We ran into this same error, and it was caused by the way we used sessions and transactions in our Web Api with NHibernate.
We should have been using session-per-request. (This can be a web request or the execution of a NServiceBus handler.) When a request starts, you should open a session and start a transaction.
We were not doing that. In our repositories, we created a new session and transaction for every database request. This meant that rather than having a single session/transaction for a request, we had many.
The root cause of the bug for us was that we were loading an entity (domain model object) in one session, modifying it, and saving it using a different session. By the time NHibernate executed the update call, the loading session/transaction had already been committed, flushed, and closed.
Solution was to pull our session/transaction creation out of the repositories and up to the Controller layer (doable using a HttpModule for REST calls and/or with aspect oriented programming using dependency injection). This one session/transaction then lives for the lifetime of the REST call or NServiceBus handler execution and is used for all database access during that call. When that call ends, it will be committed or rolled back as appropriate.
The answer given above setting the config property simply turns off DTC and reverts to the older way of doing NHibernate transactions. That may solve the problem for you if you never have to scale up your Web Api to multiple instances, but if you do, this will cause you problems.

Can I control the insert/update-command of (fluent) nhibernate to call a webservice instead of writing into the DB?

I want to use fluent-nhibernate to query my data, but when a entity gets saved, it should not be written into the database via insert/update. Instead, I want to (better: have to) serialize that object and send it to a webservice (which will map that object to a 3rd-party class that will trigger some important business-logic).
Is such behaviour possible to implement with nhibernate (call a custom method instead of update on saving)?
I would recommend creating a IRepository interface and hiding the webservice and Nhibernate functionality behind that. You could possibly use NHibernate interceptors for this, but it doesn't sound like a clean solution. Personally, I would hate to find Web service code hidden in one of Nhibernate interceptors.
We decided to use a SaveOrUpdateEventListener for this task.

Castle Windsor Interceptor and Unit Of Work

Is Castle Windsor's Inteceptor mechanism considered to be a good/effective way of implementing the Unit of Work pattern?
My project involves Castle Windsor, the NHibernate Facility and of course NHibernate - all used in self-hosted WCF services.
Each service method normally requests from the Windsor container an instance of a helper class into which the WCF call is delegated. The helper class has an ISessionManager constructor argument which Windsor resolves via the NHibernate Facility.
The trouble is, the helper class is doing too much work. It has both logic and data access intermingled which means its difficult (virtually impossible) to test and difficult to read.
What I want is to re-arrange responsibilities
I don't want the WCF helper to know anything about transactions or sessions, so no ISessionManager constructor arg, no references to transactions and no ISession.
In order for the WCF helper to do data access, its going to have to rely on a new helper, dare I call it a DAO? or God forbid a repository, on which will be methods for fetching, querying, and possibly saving domain objects.
The problem with returning NHibernate proxied objects from a DAO is that if the session is closed before the entity is returned, any subsequent attempt to access collections on the domain object from the client code will result in an exception as the session is no longer there to be used to lazily fetch the required data. It's obvious really, but everyone new to NHibernate must hit this issue.
So if DAOs and Repos cant close the session, what does?
What I need is one NHibernate session per WCF service operation call, where several DAOs or Respositories can call OpenSession as much as they like, but they all get the same session, and ideally, any attempt to dispose the session would be ignored unless its the last Dispose. Not sure about the last bit, but maybe DAOs and repos just call ISessionManager.OpenSession and leave it to something else to flush and dispose the session.
I thought maybe I could use an interceptor which takes an ISessionManager, opens a session and starts a transaction, forwards the invocation, then if no exception occurs, commits the transaction and disposes the session, otherwise rolls back the transaction if any exception occurs.
Any thoughts?
So if DAOs and Repos cant close the
session, what does?session, what does?
Services own units of work, not DAOs. They demark units of work.
Spring manages transactions using AOP, so interceptors sound like a good bet for transaction management to me.
As far as sessions go, those are UI concepts, so it ought to be the web or desktop UI controller that opens the session, marshals services to fulfill use cases, and closes the session when it's complete.
Castle.Service.Transactions also ties well together with the rest of the castle stack and allow you to use AOP to handle transactions.
Have a look at v3!
https://github.com/haf/Castle.Services.Transaction
And the wiki there!
I also created a new NHibernate Facility:
https://github.com/haf/Castle.Facilities.NHibernate/wiki/NHibernate-Facility---Quick-Start