NHibernate 1.2 is mostly source-compatible with NHibernate 1.0. However, it is not intended as a drop-in replacement for 1.0.
This document describes the changes between NHibernate 1.0 and NHibernate 1.2 that will affect existing applications, and mentions certain new features of NHibernate 1.2 that might be useful to existing applications.
Changes are classified into API changes (affecting source code), metadata changes (affecting the XML O/R mapping metadata), query language changes (affecting HQL queries), runtime behavior changes, and security-related changes.
Redundant query execution methods were deprecated in ISession interface. These methods are:
NHibernate 1.2 applications should use CreateQuery() for all query execution. Existing applications may continue to use the deprecated methods.
The overloaded forms of CreateSQLQuery() which took arrays have been deprecated. There is a new ISQLQuery interface (returned by CreateSQLQuery(String)) which provides equivalent functionality (and more). Existing applications may continue to use the deprecated methods.
The ILifecycle and IValidatable interfaces were deprecated in NHibernate 1.2 and moved to the NHibernate.Classic namespace. The Hibernate team does not consider it good practice to have domain model classes depend upon persistence-specific APIs. NHibernate 1.2 applications should use IInterceptor interface. Existing applications may continue to use ILifecycle and IValidatable.
Several new methods were added to the IInterceptor interface. Existing interceptors will need to be ugraded to provide empty implementations of the two new methods.
To avoid issues with interceptor migration (whether 1.0.x -> 1.2.x, or moving forward), just extend the new EmptyInterceptor class instead of writing your own empty implementation for all methods you don't need.
Both IUserType and ICompositeUserType had several methods added, to support new functionality of NHibernate 1.2. They were moved to the namespaceNHibernate.UserTypes. Existing user type classes will need to be upgraded to implement the new methods.
Note: NHibernate 1.2 provides IParameterizedType interface to allow better re-useability of user type implementations.
FetchMode.Lazy and FetchMode.Eager were deprecated. The more accurately named FetchMode.Select and FetchMode.Join have the same effect.
The NHibernate.Expression, NHibernate.Mapping, NHibernate.Persister and NHibernate.Collection namespaces feature heavy refactoring. Most NHibernate 1.0 applications do not depend upon these namespaces, and will not be affected. If your application does extend classes in these namespaces, you will need to carefully migrate the affected code.
Since it is best practice to map almost all classes and collections using lazy="true", that is now the default. Existing applications will need to explicitly specify lazy="false"on all non-lazy class and collection mappings. For the lazy classes to function correctly, all their public and protected members must be virtual (overridable). Since this is a very significant potential source of errors when developing on .NET, NHibernate 1.2 will check at configuration time that all lazy classes fulfill the requirements.
The outer-join attribute is deprecated. Use fetch="join" and fetch="select" instead of outer-join="true" and outer-join="false". Existing applications may continue to use theouter-join attribute, or may use a text search/replace to migrate to use of the fetch attribute.
Beware, this means you have to put lazy="false" on all collection mappings and classes which previously did not have a "lazy"-attribute.
A quick and dirty alternative for migration is also to put default-lazy="false" on all your hibernate-mapping elements.
Update the XML schema reference in your hbm XML files. Change urn:nhibernate-mapping-2.0 to urn:nhibernate-mapping-2.2 in the hibernate-mapping element. If you get "XML validation error: Could not find schema information for the element 'urn:nhibernate-mapping-2.0:hibernate-mapping'", you forgot to change the namespace.
If you have a one-to-many association to a class that is part of a subclass hierarchy (i.e. using table-per-class-hierarchy strategy), you may need to add a where attribute to the collection element since NHibernate no longer adds the discriminator restriction automatically.
This is probably best explained in code. The mapping below will no longer work as intended:
<class name="Person"> ... <!-- Cat and Dog are subclasses of Animal, mapped using <subclass> --> <bag name="Cats"> <one-to-many class="Cat" /> </bag> <bag name="Dogs"> <one-to-many class="Dog" /> </bag> </class>
To make it work again, add explicit where attributes:
<class name="Person"> ... <bag name="Cats" where="discriminator = 'CAT'"> <one-to-many class="Cat" /> </bag> <bag name="Dogs" where="discriminator = 'DOG'"> <one-to-many class="Dog" /> </bag> </class>
In NHibernate 1.0 a session acquired a database connection when needed and then held onto to it until closed. As of 1.2, however, the session will release the connection after the database transaction completes. If you are not using NHibernate transactions, the session assumes it is in auto-commit mode, and will release the connection after every operation. The session will automatically re-acquire connection the next time it is needed.
This behavior can be overridden, but typically it is best to not override this default (unless you are using NHibernate with distributed transactions, in which case the default behavior is inappropriate). If your application depends on some quirk of the old behavior (like having the same connection available beyond transaction boundaries, etc) then you may need to tweak this; but you should view this as a problem with your application logic and fix that. Or, if you believe that you can "read data without or outside of a transaction", you will likely face problems in the future versions of NHibernate. Of course, there can be no data access outside of a transaction, be it read or write access, and NHibernate will make it much more difficult to write bad code that relies on auto-commit side effects. See section "Connection Release Modes" in the documentation for more details.
The version property of a transient entity will be set to 1 when the entity is persisted (NHibernate 1.0 set the version number to 0). This was done to allow using a non-nullable type for the version property (such as Int32 or Int64), so that 0 could be used as unsaved-value for the property.
Previously, calling ISession.Get() could return an uninitialized proxy if the session contained the proxy as a result of some earlier operations. In NHibernate 1.2, Get() will initialize the proxy in this case before returning it.
ISession.Transaction property gives access to the current transaction associated with a session. Unlike previous NHibernate versions, as soon as this transaction is committed, a new transaction is associated with the session. Thus, ISession.Transaction.WasCommitted and WasRolledBack will always return false.
To be able to check the status of a particular transaction, assign it to a local variable:
ITransaction myTransaction = ISession.Transaction; ISession.Transaction.Commit(); // ISession.Transaction.WasCommitted is false here, // myTransaction.WasCommitted is true.
NHibernate 1.2 now uses Assembly.Load() instead of Assembly.LoadWithPartialName() to load driver assemblies. This means that it will no longer look for the highest-versioned assembly in the Global Assembly Cache (GAC), which was sometimes undesirable. Instead, it is now your responsibility to either put the provider assembly into the application directory, or add a qualifyAssembly element to the application configuration file, specifying the full name of the assembly.
For example, if you are using MySQL Connector/.NET, you should either put MySql.Data.dll into the application directory (or some other directory from whereAssembly.Load() can pick it up), or put it in the GAC and add a qualifyAssembly element to the configuration file:
<qualifyAssembly partialName="MySql.Data" fullName="MySql.Data, Version=..., PublicKeyToken=..."/>
In alignment with Hibernate, the count, sum and avg functions now default to return types as specified by the JPA specification. This can result in InvalidCastException 's at runtime if you used aggregation in HQL queries.
The new type rules are as follows:
If you cannot change to the new type handling the following code can be used to provide "classic" NHibernate behavior for HQL aggregation.
Configuration classicCfg = new Configuration(); classicCfg.AddSqlFunction( "count", new ClassicCountFunction()); classicCfg.AddSqlFunction( "avg", new ClassicAvgFunction()); classicCfg.AddSqlFunction( "sum", new ClassicSumFunction()); ISessionFactory classicSf = classicCfg.BuildSessionFactory();
A Disjunction with no added conditions will always evaluate to false. This is a change from 1.0 and Hibernate, where an empty disjunction evaluates to true, but we feel it is more correct.
NHibernate now uses a publicly available strong name key pair (NHibernate.snk) to strong-name binary .NET assemblies. If you relied on the key being kept private for security, you should switch to other means of assuring assembly integrity, such as using a cryptographic hash.
The original key pair used to sign NHibernate 1.0.x assemblies is still kept private.
Several assemblies have AllowPartiallyTrustedCallersAttribute (APTCA) applied to them, to make it easier to use NHibernate under Medium Trust Level. This attribute may potentially introduce security issues. To recompile NHibernate without APTCA, use this NAnt command:
nant -D:assembly.allow-partially-trusted-callers=false build