Archive

Archive for the ‘NHibernate’ Category

Deciding whether an NHibernate object reference is a proxy

November 15th, 2010 2 comments

Have you ever had a need to decide whether an object reference to an NHibernate-mapped object is the real instantiated object or an NHibernate-generated proxy used for lazy loading? Here’s how to do it:

if (entityObject is NHibernate.Proxy.INHibernateProxy)
{
  ...
}

You don’t often need to make a distinction between proxies and the real objects but it may be useful when traversing object structures without triggering lazy-loading.

A related method is NHibernateUtil.IsInitialized which may come in handy in similar use cases as the above. It tells whether a proxy or persistent collection is initialized (i.e. loaded from the database) or not.

if (NHibernateUtil.IsInitialized(entityObject))
{
  ...
}

/Emil

Categories: NHibernate Tags:

NUnit with SQLite and .Net 4.0 Beta 2

November 20th, 2009 14 comments

SQLite and unit testing is a great combination for testing database operations without having to manage database files. You can simply create an in-memory database in your setup code and work with that instance. Perfect in combination with NHibernate, for example.

If you want to do this in the current .Net 4.0 beta you’re out of luck though, you’ll get an exception:

System.IO.FileLoadException: Mixed mode assembly is built against version 'v2.0.50727' of the runtime
and cannot be loaded in the 4.0 runtime without additional configuration information.

The solution is pointed out by Jomo Fisher. What you do is to include this snippet in the application config file:

<startup useLegacyV2RuntimeActivationPolicy="true">
  <supportedRuntime version="v4.0"/>
</startup>

When unit testing assemblies that references System.Data.SQLite.DLL then you have to put that snippet in NUnit’s config file (C:\Program Files\NUnit 2.5.2\bin\net-2.0\nunit.exe.config).

If you combine this with the tip in my post NUnit with Visual Studio 2010 Beta 2, you should insert the following

<startup useLegacyV2RuntimeActivationPolicy="true">
  <supportedRuntime version="v4.0"/>
  <requiredRuntime version="v4.0.20506" />
</startup>

plus

<loadFromRemoteSources enabled="true" />

under the runtime tag.

This works for me, hopefully it will for you as well.

/Emil

Distributed transactions with WCF and NHibernate

November 13th, 2009 15 comments

I recently started working on a new project in which we wanted to use WCF services that utilized NHibernate for database work. We also wanted those services to support distributed transactions so that several calls to one or more service would be done within the same client transaction. This is possible thanks to functionality in the System.Transactions namespace and in WCF which supports transaction flowing and of course the Distributed Transaction Coordinator in the operating system (see MSDN for more info on the DTC).

Note: The code below has been tested on NHibernate 2.1.1, Windows XP and .Net 4 Beta 2. Older versions of the .Net Framework should also work, but not necessarily older versions of NHibernate. I believe distributed transaction support was introduced in 2.1.0, but it may or may not work in similar ways to what is described here in older versions since the ADO.Net supports the System.Transactions namespace.

The goal is to write code like this on the WCF client side:

// TransactionScope is from the System.Transactions namespace
using (TransactionScope tx = new TransactionScope())
{
    service1.MyMethod();
    service2.MyMethod();
    tx.Complete();
}

If all goes well, the results of both service calls are comitted to the database. If the call to service2 fails and we get an exception so that tx.Complete() is never executed, then all database updates are rolled back are rolled back and nothing is persisted, even if service1 is hosted in another process or on another machine.

Note also that we’re not limited to database updates, any resource that supports transactions and knows about System.Transactions will be able to roll back updates.

For the above to work, we have to do several things:

  • Configure the service binding to support transaction flow (on both the client and service side). Example:
    <system.serviceModel>
      <services>
        <service ... >
          <endpoint ... bindingConfiguration="TransactionalWsHttp">
             ...
          </endpoint>
          ...
        </service>
      </services>
      <bindings>
        <wshttpbinding>
          <binding name="TransactionalWsHttp" transactionFlow="true" />
        </wshttpbinding>
      </bindings>
    </system.serviceModel>
    
  • Mark the methods that should be enlisted in the distributed transaction with the TransactionFlow attribute. Do this on the service contract interface:
    [TransactionFlow(TransactionFlowOption.Allowed)]
    void SaveMyObject(Foobar object);
    

    That setting dictates that the client’s transaction will be used, if there is one. If there isn’t, a new one will be created automatically for the method call and it will be auto-committed when the method returns.

    You can also use TransactionFlowOption.Mandatory to require the client to supply the transaction. If it doesn’t then WCF will throw an exception.

  • Mark the method implementation with the OperationBehavior attribute like this:
    [OperationBehavior(TransactionScopeRequired=true)]
    public void SaveMyObject(Foobar object)
    {
       ...
    }
    

    This will supply the method with the transaction (the other settings are not enough, they simply indicate that WCF should be configured to be prepared supply the transaction and this setting says that the method really wants it).

This is actually all that is required! NHibernate will now detect if there is a so called ambient transaction (to do this yourself, look at the System.Transactions.Transaction.Current static property, if it’s non-null there there is a transaction) and will enlist its session in it. When the transaction completes, then the saved data will be comitted to the database. If there is an exception so that transaction is never completed then all data will be rolled back.

Important notes:

  • Don’t close the NHibernate ISession explicitly when using the above pattern as NHibernate will do that itself when the distributed transaction completes or is rolled back. If you do, then you will get an exception later when the transaction tries to do it.
  • Don’t create transactions explicitly, let System.Transactions do that for you.
  • If you get this error:
    Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for
    network access in the security configuration for MSDTC using the Component Services Administrative tool.
    

    then you have to do as it says and enable network access in the DTC on the server where the WCF service is hosted (and also on the database server I would assume, but I haven’t actually checked). Here’s an instruction on how to do that:
    Network access for Distributed Transaction Manager (MSDTC) has been disabled

I think this is really cool stuff. Not only does it simplify transaction management in NHibernate, it also allows us to write much more robust distributed service-oriented application with very little effort. You also get support in the operating system, for example för statistics:

DTC statistics

I haven’t tried with other databases than SQL Server but as NHibernate seems to support System.Transactions it is possible that it works with other DB systems as well. If you have any experience with that, please leave a comment :-)

I will continue to update this post if I do more findings on this subject. When I google about this there wasn’t much information on this subject so hopefully this post will help others with the same needs.

/Emil

Categories: .Net programming, NHibernate, WCF Tags:

Best practice for NHibernate: Don’t store references to ISession-instances

August 24th, 2009 2 comments

Do you see any (or all) of these exceptions (NHibernate.ADOException) in you NHibernate-based web application?

could not execute query
failed to lazily initialize a collection, no session or session was closed
Transaction not successfully started
The server failed to resume the transaction. Desc:86000002dc.

If you do, it might be a good idea to make sure you don’t store any ISession-references anywhere. If you do there’s a great risk that something goes wrong if two threads (i.e. two requests) are using the session at the same time as the NHibernate session implementation is not thread safe.

Instead, do this when an ISession is needed:

ISession session = SessionFactory.Factory.GetCurrentSession();

That code will get the session from the current context (which of course must be updated by your code, look here for more info).

/Emil

Categories: NHibernate Tags:

Distinct results sets with ICriteria in NHibernate

May 7th, 2009 No comments

If you’re using ICriteria to write queries in NHibernate and you’re having citeria on items in a one-to-many relation (e.g. retrieve all departments with at least one employee named “John”) then you’re likely to have experienced that too many objects are returned (at least more than expected). In the example, all departments with multiple “Johns” will be returned once per matching employee. This is probably not what’s expected, so here’s how to fix it:

// The 'criteria' variable contains criteria on Department

// Create alias to use for employee conditions
ICriteria aliasCriteria = criteria.CreateAlias("Employees", "pr");

// Add criteria on the alias...

// We only want distinct root objects returned
criteria.SetResultTransformer(Transformers.DistinctRootEntity);

The trick is to use Transformers.DistinctRootEntity (at least in NHibernate 2.1). In earlier versions you may want to try something like this:

criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());

Related to this is also how to write criteria that counts the results without actually retrieving them, which can be very useful for paging the result set (i.e. only read a subset of the results at a time). Normally you would write something like this:

criteria.SetProjection(Projections.Count("Id"));
int numberOfItems = (int)criteria.UniqueResult();

However, this suffers from the same problem as described above. To get the correct result, do this:

criteria.SetProjection(Projections.CountDistinct("Id"));
int numberOfItems = (int)criteria.UniqueResult();

Problem solved!

Credits to my colleague Jon for helping out with these rather obscure problem solutions!

/Emil

Categories: NHibernate Tags:

hibernate.cfg.xml not found in ASP.Net application?

April 16th, 2009 No comments

In later versions of NHibernate it’s possible to separate NHibernate configuration from normal application configuration (which is normally done in App.config/Web.config) by using a separate file called hibernate.cfg.xml.

Works great, but there is one thing to keep in mind in ASP.Net applications, namely that it should be placed in the bin/ folder, not in the root folder fo the application! Took me quite some time to figure out! So if you have the same problem as me, just move it to that folder :-)

/Emil

Categories: NHibernate Tags:
Web Analytics