Browsing Posts published in January, 2011

We’ve all done it at one point or another. Our application throws an exception and we start wading through a standard Windows error dialog or a log file to examine the exception and stack trace. If you’re a ReSharper Jedi, you’ve probably copied the exception and stack trace to the clipboard and hit CTRL-SHIFT-E (IDEA) or CTRL-E, T (VS) in Visual Studio to launch ReSharper’s Stack Trace Explorer. (If you have’t, you’ll see the Stack Trace Explorer in just a second.)

Let me show you an easier way that works well on desktop or Silverlight apps. I’ll use Silverlight for demo purposes, but the same technique works with WPF and WinForms. First we need to hook up a global error handler:

public MainPage() {
    InitializeComponent();
    Application.Current.UnhandledException += HandleApplicationUnhandledException;
}

private static void HandleApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) {
    if(Debugger.IsAttached) {
        Clipboard.SetText(e.ExceptionObject.ToString());
    }
    e.Handled = false;
}

Please note that this is demo code and I’m simply hooking this up in the code behind. In a larger application, I would typically publish an ErrorOccurred message to my application’s message bus and register a listener that would contain the code in HandleApplicationUnhandledException.

Notice that I’m checking whether a debugger is attached. If so, I place the contents of the System.Exception (or derived exception) on the clipboard. (Clipboard is in the System.Windows namespace for Silverlight and WPF apps, but there is an identically-named class in System.Windows.Forms.) The reason that I’m checking whether a debugger is attached is so that end-users don’t get the clipboards spammed with exception text. You could conditionally compile the code so that production builds don’t contain it, but personally I like having the code in production too. It means that I can grab an old build, attach a debugger, and get the same exceptions that the end users are getting.

Now that the exception and stack trace is on the clipboard, I jump over to Visual Studio and press CTRL-SHIFT-E (IDEA) or CTRL-E, T (VS). I am immediately presented with ReSharper’s Stack Trace Explorer as ReSharper is smart enough to grab the current clipboard contents to display:

StackTraceExplorer

The advantage here is fictionless debugging as you no longer have to find, select, and copy the exception and stack trace to the clipboard. It’s there for you automatically. As soon as you hit an exception, simply jump to Visual Studio and press CTRL-SHIFT-E (IDEA) or CTRL-E, T (VS) and you’re ready to find the problem. Also note that all the method names in the ReSharper’s Stack Trace Explorer are hot links to the appropriate code file allowing for easy navigation of your code base, the .NET Framework, and third-party libraries.

One quick note regarding Silverlight… Many modern browsers (e.g. FF4, IE8+, Chrome, …) will run Silverlight in a separate process. So even when you launch with debugging (F5), you’ll be attached to the browser process itself and not the child process that is hosting Silverlight. To correct this, simply go to Debug… Attach to Process… and find the hosting process where the type is Silverlight. (For FireFox 4, the hosting process is called plugin-container.exe. For IE8+ and Chrome, the hosting process is called iexplore.exe or chrome.exe, respectively. Just look for the one hosting Silverlight as noted under the “Type” column.)

AttachToProcess

Happy Debugging!

[Code for this article is available on GitHub here.]

In this post, we’ll examine the ways that NHibernate supports the DateTime-related data types, including some new features introduced in NHibernate 2 and 3. Here is a quick summary for the impatient.

DbType .NET SQL Type
DateTime System.DateTime datetime
LocalDateTime System.DateTime datetime
UtcDateTime System.DateTime datetime
DateTimeOffset System.DateTimeOffset datetimeoffset
DateTime2 System.DateTime datetime2
Date System.DateTime date
Time System.DateTime time
TimeAsTimeSpan System.TimeSpan time
TimeSpan System.TimeSpan bigint (int64)

Local/UTC

Let’s take a look at a few DateTime-related problems that developers have run into in the past…

public class DateTimeEntity {
    public DateTimeEntity() {
        CreationTime = DateTime.Now;
    }

    public virtual Guid Id { get; private set; }
    public virtual DateTime CreationTime { get; set; }
}

Note that CreationTime is initialized using DateTime.Now. The corresponding mapping file would be:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

namespace="Nh3Hacking"

assembly="Nh3Hacking"> <class name="DateTimeEntity"> <id name="Id"> <generator class="guid.comb" /> </id> <property name="CreationTime"/> </class> </hibernate-mapping>

If we create an instance of our DateTimeEntity and reload it, we get:

Original entity:
Id: 09bead07-5a05-4459-a108-9e7501204918
        CreationTime: 2011-01-24 5:29:36 PM (Local)
Reloaded entity:
Id: 09bead07-5a05-4459-a108-9e7501204918
        CreationTime: 2011-01-24 5:29:36 PM (Unspecified)

Note that I am outputting both CreationTime.ToString() and CreationTime.Kind. DateTime.Kind returns a DateTimeKind (surprising, huh?), which indicates whether this DateTime represents Local time or UTC time. We initialized the value with DateTime.Now, which is the local time. (If we wanted UTC time, we would use DateTime.UtcNow.) When the object is reloaded, the DateTimeKind is Unspecified. This is because the database does not store whether the DateTime value is Local or UTC. NHibernate has no way of knowing which one it is, hence Unspecified.

NHibernate 3 includes two new DbTypes that allow us to resolve this ambiguity. In our mapping file, we can write:

<property name="CreationTimeAsLocalDateTime" type="LocalDateTime"/>
<property name="CreationTimeAsUtcDateTime" type="UtcDateTime"/>

We are explicitly telling NHibernate whether the database stores Local or UTC times.

Original entity:
Id: 09bead07-5a05-4459-a108-9e7501204918
        CreationTimeAsDateTime: 2011-01-24 5:29:36 PM (Local)
        CreationTimeAsLocalDateTime: 2011-01-24 5:29:36 PM (Local)
        CreationTimeAsUtcDateTime: 2011-01-25 12:29:36 AM (Utc)
Reloaded entity:
Id: 09bead07-5a05-4459-a108-9e7501204918
        CreationTimeAsDateTime: 2011-01-24 5:29:36 PM (Unspecified)
        CreationTimeAsLocalDateTime: 2011-01-24 5:29:36 PM (Local)
        CreationTimeAsUtcDateTime: 2011-01-25 12:29:36 AM (Utc)

This is strictly metadata and it is up to the developer to ensure that the proper DateTime is present in the property/field. For instance, if I initialize the entity as follows:

public DateTimeEntity() {
    CreationTimeAsDateTime = DateTime.Now;
    CreationTimeAsLocalDateTime = DateTime.UtcNow;
    CreationTimeAsUtcDateTime = DateTime.Now;
}

Note that the LocalDateTime property contains a UTC DateTime and the UTC property contains a Local DateTime. The results are:

Original entity:
Id: 4579d245-46f3-4c3f-893b-9e750124a90b
        CreationTimeAsDateTime: 2011-01-24 5:45:32 PM (Local)
        CreationTimeAsLocalDateTime: 2011-01-25 12:45:32 AM (Utc)
        CreationTimeAsUtcDateTime: 2011-01-24 5:45:32 PM (Local)
Reloaded entity:
Id: 4579d245-46f3-4c3f-893b-9e750124a90b
        CreationTimeAsDateTime: 2011-01-24 5:45:32 PM (Unspecified)
        CreationTimeAsLocalDateTime: 2011-01-25 12:45:32 AM (Local)
        CreationTimeAsUtcDateTime: 2011-01-24 5:45:32 PM (Utc)

Notice that NHibernate did not perform any conversions or throw an exception when saving/loading a DateTime value with the wrong DateTimeKind. (It could be argued that NHibernate should throw an exception when asked to save a Local DateTime and the property is mapped as a UtcDateTime.) It is up to the developer to ensure that the proper kind of DateTime is in the appropriate field/property.

System.DateTimeOffset

One problem that LocalDateTime and UtcDateTime does not solve is the offset problem. If you have a DateTime and its Kind is Local, all you know is that it is a Local DateTime. You do not know if that Local DateTime is Mountain (MST), Eastern (EST), Pacific (PST), etc. You do not know whether it has been corrected for daylight savings time. All you know is that it is a Local DateTime. You have to assume that the local time is based on the time zone of the current computer. Although this is often a reasonable assumption, it’s not always. (Consider for example that you’re collecting log files from a distributed system and servers reside in multiple time zones.) The problem is that System.DateTime class does not contain a place to record the timezone offset. Microsoft solved this problem starting in .NET 3.5 by introducing the System.DateTimeOffset class. It looks a lot like System.DateTime, but does include the timezone offset rather than the DateTimeKind. So we can just use System.DateTimeOffset in our applications rather than System.DateTime.

Except… Date/time types in SQL databases do not have anywhere to store the timezone offset. The notable exception is SQL Server 2008, which introduced the datetimeoffset type. NHibernate 2 introduced support for System.DateTimeOffset, but only for SQL Server 2008 onwards. (If you’re using SQL Server 2005 or earlier or another database server, you’ll have to implement your own IUserType to store System.DateTimeOffset in two separate columns – one for the DateTime and the other for the timezone offset.) The additional code in DateTimeEntity.cs looks like this:

public virtual DateTimeOffset CreationTimeAsDateTimeOffset { get; set; }

The mapping file just needs the new property added:

<property name="CreationTimeAsDateTimeOffset"/>

Note that I don’t need to specify the type in the mapping as NHibernate can infer it from the property type in DateTimeEntity. The resulting output is:

Original entity:
Id: 95aa6c15-86f5-4398-aa9e-9e7600ae4580
        CreationTimeAsDateTime: 2011-01-25 10:34:30 AM (Local)
        CreationTimeAsLocalDateTime: 2011-01-25 10:34:30 AM (Local)
        CreationTimeAsUtcDateTime: 2011-01-25 5:34:30 PM (Utc)
        CreationTimeAsDateTimeOffset: 2011-01-25 10:34:30 AM -07:00
Reloaded entity:
Id: 95aa6c15-86f5-4398-aa9e-9e7600ae4580
        CreationTimeAsDateTime: 2011-01-25 10:34:30 AM (Unspecified)
        CreationTimeAsLocalDateTime: 2011-01-25 10:34:30 AM (Local)
        CreationTimeAsUtcDateTime: 2011-01-25 5:34:30 PM (Utc)
        CreationTimeAsDateTimeOffset: 2011-01-25 10:34:30 AM -07:00

Support for DateTime2, Date, and Time

Let’s look at some C# and the corresponding mapping file for these types:

public virtual DateTime CreationTimeAsDateTime2 { get; set; }
public virtual DateTime CreationTimeAsDate { get; set; }
public virtual DateTime CreationTimeAsTime { get; set; }
public virtual TimeSpan CreationTimeAsTimeAsTimeSpan { get; set; }
public virtual TimeSpan CreationTimeAsTimeSpan { get; set; }

Modifications to the hbm.xml:

<property name="CreationTimeAsDateTime2" type="DateTime2"/>
<property name="CreationTimeAsDate" type="Date"/>
<property name="CreationTimeAsTime" type="Time"/>
<property name="CreationTimeAsTimeAsTimeSpan" type="TimeAsTimeSpan"/>
<property name="CreationTimeAsTimeSpan"/>

We’ll examine each of these in turn…

DbType.DateTime2 is a higher precision, wider range version of DbType.DateTime. DbType.DateTime maps to the datetime (or smalldatetime) SQL type, which has a range of 1753-01-01 to 9999-12-31. DbType.DateTime2 maps to the datetime2 SQL type, which has a range of 0001-01-01 to 9999-12-31. (Precision can be as high as 1/10 of a microsecond with a datetime2(7).) One of the niceties of DateTime2 is that an uninitialized DateTime struct (which has a value of 0001-01-01 12:00:00 AM (Unspecified)) does not cause a SqlTypeException with a SqlDateTime underflow.

DbType.Date does just what it advertises. It represents a Date without a Time component. It is stored in the database as only a date. .NET does not have a Date type and NHibernate represents it via a DateTime with the time portion set to 12:00:00 AM. I personally prefer to define my own Date class, which has no time component, and create an IUserType to handle the mapping. My custom Date class can handle the time truncation and provide a more natural programing model for my domain, but that’s a post for another day.

Time-related DbTypes stores just the time, but no date. In .NET, there is no Time class and so NHibernate uses a DateTime with the date component set to 1753-01-01, the minimum value for a SQL datetime or a System.TimeSpan – depending on the DbType that we choose. DbType.Time stores a System.DateTime in a time SQL type. DbType.TimeAsTimeSpan stores a System.TimeSpan as a time SQL type. DbType.TimeSpan stores a Syste.TimeSpan as a 64-bit integer (bigint) SQL type. As I mentioned for DbType.Date, I am more inclined to write my own Time class and custom IUserType to achieve a better programming model than relying on the .NET constructs of System.DateTime and System.TimeSpan. (I typically use System.DateTime or System.TimeSpan as a field in my custom Date or Time class for storing the data, but provide my own API for consistently working with the data.)

WARNING: Not all databases support all date/time SQL types. So before choosing .NET and SQL types for your entities, make sure that they’re available in all databases that you plan to support.

Now we’ll take a look at these date/time types in action:

Original entity:
Id: 6b2fb9ff-8036-4c17-b9ef-9e7600bf37e3
        CreationTimeAsDateTime: 2011-01-25 11:36:12 AM (Local)
        CreationTimeAsLocalDateTime: 2011-01-25 11:36:12 AM (Local)
        CreationTimeAsUtcDateTime: 2011-01-25 6:36:12 PM (Utc)
        CreationTimeAsDateTimeOffset: 2011-01-25 11:36:12 AM -07:00
        CreationTimeAsDateTime2: 2011-01-25 11:36:12 AM (Local)
        CreationTimeAsDate: 2011-01-25 11:36:12 AM (Local)
        CreationTimeAsTime: 2011-01-25 11:36:12 AM (Local)
        CreationTimeAsTimeAsTimeSpan: 11:36:12.2688265
        CreationTimeAsTimeSpan: 11:36:12.2688265
Reloaded entity:
Id: 6b2fb9ff-8036-4c17-b9ef-9e7600bf37e3
        CreationTimeAsDateTime: 2011-01-25 11:36:12 AM (Unspecified)
        CreationTimeAsLocalDateTime: 2011-01-25 11:36:12 AM (Local)
        CreationTimeAsUtcDateTime: 2011-01-25 6:36:12 PM (Utc)
        CreationTimeAsDateTimeOffset: 2011-01-25 11:36:12 AM -07:00
        CreationTimeAsDateTime2: 2011-01-25 11:36:12 AM (Unspecified)
        CreationTimeAsDate: 2011-01-25 12:00:00 AM (Unspecified)
        CreationTimeAsTime: 1753-01-01 11:36:12 AM (Unspecified)
        CreationTimeAsTimeAsTimeSpan: 11:36:12.2700000
        CreationTimeAsTimeSpan: 11:36:12.2688265

Summary

As you have seen, NHibernate has a wide variety of options for mapping date/time-related types to and from the database. The right choice is highly dependent on your application and database server. I hope that this post has given you a few more tricks up your sleeve for effectively mapping date/time-related types using NHibernate.

[Code for this article is available on GitHub here.]

One of the new features in NHibernate 3 is the addition of a fluent API for configuring NHibernate through code. Fluent NHibernate has provided a fluent configuration API for awhile, but now we have an option built into NHibernate itself. (Personally I prefer the new Loquacious API to Fluent NHibernate’s configuration API as I find Loquacious more discoverable. Given that Fluent NHibernate is built on top of NHibernate, you can always use Loquacious with Fluent NHibernate too. N.B. I still really like Fluent NHibernate’s ClassMap<T>, automapping capabilities, and PersistenceSpecification<T>. So don’t take my preference regarding fluent configuration as a denouncement of Fluent NHibernate.)

The fluent configuration API built into NHibernate is called Loquacious configuration and exists as a set of extensions methods on NHibernate.Cfg.Configuration. You can access these extension methods by importing in the NHibernate.Cfg.Loquacious namespace.

var cfg = new Configuration();
cfg.Proxy(p => p.ProxyFactoryFactory<ProxyFactoryFactory>())
   .DataBaseIntegration(db => {
                            db.ConnectionStringName = "scratch";
                            db.Dialect<MsSql2008Dialect>();
                            db.BatchSize = 500;
                        })
   .AddAssembly(typeof(Blog).Assembly)
   .SessionFactory().GenerateStatistics();

On the second line, we configure the ProxyFactoryFactory, which is responsible for generating the proxies needed for lazy loading. The ProxyFactoryFactory type parameter (stuff between the <>) is in the NHibernate.ByteCode.Castle namespace. (I have a reference to the NHibernate.ByteCode.Castle assembly too.) So we’re using Castle to generate our proxies. We could also use LinFu or Spring.

Setting db.ConnectionStringName causes NHibernate to read the connection string from the <connectionStrings/> config section of the [App|Web].config. This keeps your connection strings in an easily managed location without being baked into your code. You can perform the same trick in XML-based configuration by using the connection.connection_string_name property instead of the more commonly used connection.connection_string.

Configuring BatchSize turns on update batching in databases, which support it. (Support is limited to SqlClient and OracleDataClient currently and relies on features of these drivers.) Updating batching allows NHibernate to group together multiple, related INSERT, UPDATE, or DELETE statements in a single round-trip to the database. This setting isn’t strictly necessary, but can give you a nice performance boost with DML statements. The value of 500 represents the maximum number of DML statements in one batch. The choice of 500 is arbitrary and should be tuned for your application.

The assembly that we are adding is the one that contains our hbm.xml files as embedded resources. This allows NHibernate to find and parse our mapping metadata. If you have your metadata located in multiple files, you can call cfg.AddAssembly() multiple times.

The last call, cfg.SessionFactory().GenerateStatistics(), causes NHibernate to output additional information about entities, collections, connections, transactions, sessions, second-level cache, and more. Although not required, it does provide additional useful information about NHibernate’s performance.

Notice that there is no need to call cfg.Configure(). cfg.Configure() is used to read in configuration values from [App|Web].config (from the hibernate-configuration config section) or from hibernate.cfg.xml. If we’ve not using XML configuration, cfg.Configure() is not required.

Loquacious and XML-based configuration are not mutually exclusive. We can combine the two techniques to allow overrides or provide default values – it all comes down to the order of the Loquacious configuration code and the call to cfg.Configure().

var cfg = new Configuration();
cfg.Configure();
cfg.Proxy(p => p.ProxyFactoryFactory<ProxyFactoryFactory>())
   .SessionFactory().GenerateStatistics();

Note the cfg.Configure() on the second line. We read in the standard XML-based configuration and then force the use of a particular ProxyFactoryFactory and generation of statistics via Loquacious configuration.

If instead we make the call to cfg.Configure() after the Loquacious configuration, the Loquacious configuration provides default values, but we can override any and all values using XML-based configuration.

var cfg = new Configuration();
cfg.Proxy(p => p.ProxyFactoryFactory<ProxyFactoryFactory>())
   .DataBaseIntegration(db => {
                            db.ConnectionStringName = "scratch";
                            db.Dialect<MsSql2008Dialect>();
                            db.BatchSize = 500;
                        })
   .AddAssembly(typeof(Blog).Assembly)
   .SessionFactory().GenerateStatistics();
cfg.Configure();

You can always mix and match the techniques by doing some Loquacious configuration before and som after the call to cfg.Configure().

WARNING: If you call cfg.Configure(), you need to have <hibernate-configuration/> in your [App|Web].config or a hibernate.cfg.xml file. If you don’t, you’ll throw a HibernateConfigException. They can contain an empty root element, but it needs to be there. Another option would be to check whether File.Exists(‘hibernate.cfg.xml’) before calling cfg.Configure().

So there you have it. The new Loquacious configuration API in NHibernate 3. This introduction was not meant as a definitive reference, but as a jumping off point. I would recommend that you explore other extension methods in the NHibernate.Cfg.Loquacious namespace as they provide the means to configure the 2nd-leve cache, current session context, custom LINQ functions, and more. Anything you can do in XML-based configuration can now be accomplished with Loquacious or the existing methods on NHibernate.Cfg.Configuration. So get out there and start coding – XML is now optional…