Category name´╝ÜNHibernate

WCF and DateTime.Kind pitfall

At my job (Company Webcast) we have several API’s for our customers to use. One of those API’s allow webcasts to be created and modified and that interface has data containing dates. Our platform works with UTC date time’s as we are an international operating company so it is logical for use to store those as UTC.

We use WCF and yesterday we had a very weird issue where calls failed. After investigating the issue we found out that the cause was that how the date time got supplied to our service in the message

The following values are valid in an XML message:

<ns1:ScheduledStart>2010-05-26T17:00:00+02:00</ns1:ScheduledStart>

<ns1:ScheduledStart>2010-05-26T15:00:00Z</ns1:ScheduledStart>

A WCF service accepts both values but it treats them different which I did not expect! The first value became 2010-05-26 17:00 where DateTime.Kind is set to Local and the second becomes 2010-05-26 15:00 with DateTime.Kind set to UTC. This amazed me a bit as I assumed that both would always result in either a UTC or Local DateTime.

The reason it fails is that another argument states the time-zone from where the live webcast will be held. This is used in combination with the DateTime to convert the DateTime value to a local time to inform the viewer about the conditions of the event. This code assumed that the incoming DateTime value would always be of kind UTC.

So now our front-end api’s convert incoming DateTime values to a DateTime value with kind UTC.

This could also be a problem when you persist this DateTime to for example a database and your storage logic does not convert the DateTime from/to UTC or Local depending on your needs. We use NHibernate for storage and it does not by default has a way to set UTC/Local to a <property> definition. This can really become a problem when time is part of your business logic as it is in ours as we use it to schedule tasks and it is very important to know it a time is UTC or not especially when something happens on the other side of the world.

How to perform a not equals comparison with NHibernate criteria api

I often hear that NHibernate is not usable for selecting records as it is not possible to perform a not equal comparison with the criteria api. I must admin that it took me a while before I found out but it really is more logical when you know. Lets take a look at the following example:

// Select entries where name = "Ramon"
var criteria = DetachedCriteria.For<MyCoolClass>()
.Add(Restrictions.Eq("Name", "Ramon"));

Your first reaction it to find the opposite of Restrictions.Eq but then you are amazed that it does not exists. The solution is so simple that it will almost embares you:

 

// Select entries where name != "Ramon"
var criteria = DetachedCriteria.For<MyCoolClass>()
.Add(!Restrictions.Eq("Name", "Ramon"));

 

Do you see the difference? I added an exclamation mark before Restrictions.Eq to invert the restrictions operator.

So now you know and probably never forget ­čśë

 

 

Speeding up startup time for applications that use NHibernate

I just read a very cool NHibernate trick to let your application start faster that was mentioned by Ricardo Peres:

Configuration cfg = new Configuration().Configure();
IFormatter serializer = new BinaryFormatter();

using (Stream stream = File.OpenWrite("Configuration.serialized"))
{
   serializer.Serialize(stream, cfg);
}

...

using (Stream stream = File.OpenRead("Configuration.serialized"))
{
   cfg = serializer.Deserialize(stream) as Configuration;
}

NHibernate bag did not delete records when IList.Clear() was called

I was having a problem where NHibernate did not automatically delete childs if a collection was emptied by calling IList.Clear() like in the following code example:

var s = GetSession();
var parent = s.Get<Parent>(1);
parent.Childs.Clear();

What did work ofcourse was code like the following before executing clear which marked the records for deletion and NHibernate executed the correct delete statements when the session was closed or flushed.

foreach(var c in parent.Childs) s.Delete(c);

I searched the internet for quite a while and playing around with the cascade and inverse attributes in the .hbm files as I knew it had be an error in the configuration.

<bag name="Topics" cascade="all" inverse="true">
	<key column="Webcast_Id"/>
	<one-to-many class="AddonIndex"/>
</bag>

After searching for quite some time I found that the problem was cascade=”all” which should have been cascade=”all-delete-orphan” and when I read that on a forum I had a very bigy WTF moment. I *really* assumed that all would do the deletion of the orphans as that is what the keyword implies, that it does *all* while in reality it does all except deletion of orphans.

So I would like to suggest the (N)Hibernate team to change the names of the cascade values or just ditch the all value.

NHibernate implicit join quirk

Recently I had a problem where in an HQL query the result contained duplicates. I used implicit joins in the my query and it looked like the following:

from
    Order o
where
    (o.Code like :literal
    OR o.CustomData like :literal
    OR o.Customer.Code like :literal
    OR o.Customer.Name like :literal)

This HQL got translated to the following TSQL query:

select
    order0_.* — all order columns removed for readability
from
    nhtest.dbo.Order order0_,
    nhtest.dbo.Customer customer0_
where
    (order0_.Code like @p0 )
    OR(order0_.CustomData like @p1 )
    OR(customer0_.Code like @p2  and order0_.CustomerId=customer0_.Id) — Incorrect join!
    OR(customer0_.Name like @p3  and order0_.CustomerId=customer0_.Id) — Incorrect join!

The join isn’t correct as it should have been the following:

select
    order0_.* — all order columns removed for readability
from
    nhtest.dbo.Order order0_,
    JOIN nhtest.dbo.Customer customer0_ ON (order0_.CustomerId=customer0_.Id)
where
    order0_.Code like @p0 )
    OR(order0_.CustomData like @p1 )
    OR(customer0_.Code like @p2)
    OR(customer0_.Name like @p3)
)

The (N)Hibernate documentation says that it is better to make use of the explicit join syntax and that is working correct. So do not use implicit joins (well, atleast not in version 2.0.0.GA)!

  • Recent Posts
  • Recent Comments
  • Archives
  • Categories
  • Meta