Comparing which is better

I received an email asking

I am comparing “MicroLite 6.2.5” with EF & nhibernate for PostgreSQL.

May I ask you in two lines, why “MicroLite 6.2.5” is better?

Unfortunately it’s not actually possible to answer that question without actually defining how are we measuring “better”.

What would have been more sensible would have been to ask “How are they different?” and then compare the features each offers and the pros and cons to decide which is better for you.

Looking ahead to MicroLite 7.0

You may have noticed that there hasn’t been a lot going on recently with MicroLite, we’ve had a few bug fixes since version 6.2 was released but nothing big. There are 2 main reasons behind that, the first is that I’ve been busy with some other things and the second is that I’ve been thinking about where to take MicroLite next.

There’s nothing concrete at the moment, but the main things I would like to do are:

  • Move to .NET Core
  • Support multiple mapping conventions (similar to how the attribute and convention routing works in ASP.NET Web API)
  • Support immutable and private types
  • Go async only
  • Move the other database providers into separate assemblies which can reference the 3rd party libraries (instead of everything working against DbCommand and DbParameter)
  • Allow custom instance factories
  • Support out parameters from stored procedures
  • Replace the MVC and WebApi extensions with a single AspNet extension for ASP.NET 5 (vNext)

That’s by no means a complete list, if there’s anything you would like to see added or any concerns with anything on that list, please comment here or raise an issue on the GitHub site.

Upgrading to MicroLite 6.2

MicroLite 6.2.0 has been released on NuGet.

The 2 main changes in this release are:

  • The session re-uses the same command during its lifecycle so multiple operations via a session are more efficient – especially multiple operations of the same type (e.g. multiple inserts).
  • Improved the handling of TimeSpan – beware that this is a breaking change (see below)

Prior to MicroLite 6.2, MicroLite was able to map a TimeSpan to a MS SQL Time column – however it turns out there are a number of problems with the Time type:

  1. It has a maximum value of 24:00:00 since it is actually designed to represent the time of day
  2. It cannot be used in some aggregate functions such as SUM and AVERAGE which makes summarising data diffucult

In order to mitigate these issues, MicroLite 6.2 now maps TimeSpan to a BIGINT by persisting the tick count of the TimeSpan – this has the side effect of also enabling TimeSpan to be used by any database supported by MicroLite.

If you are updating to MicroLite 6.2 and you are currently using TimeSpan -> TIME you have 2 options:

1) – Update your database schema to use a BIGINT (add a new column, populate it by casting the time as the tick count, remove the old column).

2) – Configure MicroLite 6.2 to behave like MicroLite 6.1:

// In startup code (before calling Configure.Fluently()...):

// 1. Remove the new TimeSpanTypeConverter:
var timeSpanTypeConverter = TypeConverter.Converters.OfType<TimeSpanTypeConverter>().Single();

// 2. Reset the DbType mapping for TimeSpan:
TypeConverter.RegisterTypeMapping(typeof(TimeSpan), System.Data.DbType.Time);
TypeConverter.RegisterTypeMapping(typeof(TimeSpan?), System.Data.DbType.Time);

Understanding InvalidCastException

We can sometimes get an InvalidCastException thrown when reading a record from the database, the usual reason for this is that the database column does not match the property type on the class. For example, we have a column defined in the database as:

PhoneNumber int not null

and in the class we have

public string PhoneNumber { get; set; }

The reason this will fail is that MicroLite will read the value using the most efficient method and since the property is a string and IDataReader has a method GetString that will be called, essentially doing this:

obj.PhoneNumber = dataReader.GetString(idx);

However since the actual returned value in the IDataReader is an int which cannot be implicitly cast to a string we get an InvalidCastException. To resolve this, change the property type and database column to be compatible types (e.g. change the database column to string or change the class property to int).

MicroLite 6.0 Logging/Debugging

One of the things we focused on in MicroLite 6.0 is making the logging and debugging process even nicer for developers.

Since very early on MicroLite has had support for writing to your application log via the logging extension packages. However it has never been easy to see how a class has been mapped. To make this easier to understand, we have created an extension method for IObjectInfo which can be used to write the mapping to a TextWriter. We also write this to the log if the log is capturing Debug statements.

It’s as easy as this:

// Resolve the IObjectInfo for the mapped class.
var objectInfo = ObjectInfo.For(typeof(Customer));

// Write the mappings to the console
// or write the mappings to a string
var stringWriter = new StringWriter()

// Write mappings to a TextWriter
var mappingDetails = stringWriter.ToString();

For the following class using the default conventions:

public class Customer
    public int Id { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public DateTime DateOfBirth { get; set; }
    public CustomerStatus Status { get; set; }

It will emit the following:

MicroLite Mapping:
Class ‘MyApplication.Customer’ mapped to Table ‘Customers’

Property ‘DateOfBirth (System.DateTime)’ mapped to Column ‘DateOfBirth (DbType.DateTime)’
Allow Insert: True
Allow Update: True
Is Identifier: False

Property ‘Forename (System.String)’ mapped to Column ‘Forename (DbType.String)’
Allow Insert: True
Allow Update: True
Is Identifier: False

Property ‘Id (System.Int32)’ mapped to Column ‘Id (DbType.Int32)’
Allow Insert: False
Allow Update: False
Is Identifier: True
Identifier Strategy: DbGenerated

Property ‘Status (ConsoleApplication5.CustomerStatus)’ mapped to Column ‘CustomerStatusId (DbType.Int32)’
Allow Insert: True
Allow Update: True
Is Identifier: False

Property ‘Surname (System.String)’ mapped to Column ‘Surname (DbType.String)’
Allow Insert: True
Allow Update: True
Is Identifier: False

MicroLite OData update

The latest release of MicroLite.Extensions.WebApi (6.1) and Net.Http.WebApi.OData (3.1) now provide support for nearly the entire OData 3 spec that can be supported by MicroLite.

It is now possible to compare 2 properties:

$filter=FirstName eq LastName

And call nested functions:

$filter=concat(concat(City, ', '), Country) eq 'Berlin, Germany'

Decimal/Double and Single values don’t require .0 for whole values:

$filter=Price eq 5M can now be used as well as $filter=Price eq 5.0M

Method parameters no longer require a space after the comma:

$filter=endswith(CompanyName,'Futterkiste’) can now be used as well as
$filter=endswith(CompanyName, 'Futterkiste')

Literal strings (text wrapped in single quotes) can now contain a single quote by escaping it with another single quote:

$filter=LastName eq ‘O’’Brien’

Grouping is now supported in queries:

$filter=LastName eq 'Smith' and (Title eq 'Mr' or Title eq 'Mrs')

Without the grouping, the query would be translated as:

LastName = Smith and Title = Mr
Title = Mrs

There is no concept of an “in list” in OData so a grouped set of “or”s is the way to achieve the same result.

endswith, startswith, and substringof now no longer require eq true at the end:

startswith(CompanyName,’Alfr’) is the same as startswith(CompanyName,’Alfr’) eq true

The not operator has also been implemented which means you can negate function calls:

not startswith(CompanyName,’Alfr’)


Since very early on MicroLite has had support for writing to your application log via the MicroLite.Logging.Log4Net or MicroLite.Logging.NLog.

With the release of MicroLite 6.1 we have added support for Serilog via the MicroLite.Logging.Serilog package.

You can see the details of how to configure it on the GitHub site.

Please note that whilst this will enable MicroLite to write to your log, it doesn’t support the usual Serilog format log messages so the statements will be formatted strings.

For example, you would see

Beginning a new Transaction with the IsolationLevel 'ReadCommitted'

In the log rather than

Beginning a new Transaction with the IsolationLevel '{isolationLevel}'

This is because MicroLite does not know which if any logging library it will be writing to at runtime so it has to use standard .NET format strings for its log messages.