ASP.NET

Manipulation de dates en UTC avec Entity Framework.

Avr 19, 2012

Ludovic Nascimbeni

Bien souvent lorsque l’on manipule des dates coté serveur, qu’il s’agisse de les stocker en base de données ou bien d’effectuer des traitements dessus on choisit de n’utiliser que de l’UTC, afin d’avoir un référentiel commun à tous les fuseaux horaires.
Cependant lorsque l’on utilise Entity Framework, on est confronté à un problème.

En effet, par défaut, lorsque EF mappe un champ datetime SQL à une propriété DateTime d’une entité, la valeur de la propriété Kind (Unspecified / LocalTime / Utc) est positionnée à Unspecified.

Ceci est tout à fait logique étant donné que le type datetime SQL ne contient pas d’information relative au fuseau horaire.
Cela s’avère très ennuyeux lorsque l’on travaille sur une architecture n-tier car lorsque l’entité sera déserialisée coté client, le moteur de sérialisation WCF (DataContractSerializer) va partir du principe que la valeur Unspecified correspond à du LocalTime.
Vous allez donc vous retrouver coté client avec une date exprimée en UTC mais qui indique qu’elle est en LocalTime.

Pour remédier à ce problème, il suffit de modifier un peu le T4 qui génère les entités (et l’ObjectContext par la même occasion si vous ne les avez pas séparés ^^).
On va juste appeler la méthode statique SpecifyKind de du type DateTime dans le setter de toutes les propriétés de type DateTime des entités coté serveur afin de forcer la propriété Kind en UTC.
Ce code ne doit être éxécuté que lorsque la propriété est set pour la première fois.

dans le cas d’un DateTime :

_updateDate = _updateDate == new DateTime() ? DateTime.SpecifyKind(value.Value, DateTimeKind.Utc) : value;

dans le cas d’un Nullable<DateTime> :

_updateDate = _updateDate == null ? DateTime.SpecifyKind(value.Value, DateTimeKind.Utc) : value;

Pour pouvoir générer ce code au niveau de vos entités il faut que vous ayez au préalable récupéré un des templates de T4 d’EF que vous pourrez trouver via l’ExtensionManager de Visual Studio (avec le template par défaut vous n’aurez pas accès au T4).

Il ne vous reste plus qu’à localiser le code permettant de générer les propriétés des entités puis de remplacer la ligne suivante <#=code.FieldName(edmProperty)#> = value; par ce code :

if (((PrimitiveType)edmProperty.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.DateTime)
			{
#>
				<#=code.FieldName(edmProperty)#> = <#+
				if (ef.IsNullable(edmProperty))
				{
#>
<#=code.FieldName(edmProperty)#> == null ? DateTime.SpecifyKind(value.Value, DateTimeKind.Utc) : <#+
			   }
			   else
			   {
#>
<#=code.FieldName(edmProperty)#> == new DateTime() ? DateTime.SpecifyKind(value, DateTimeKind.Utc) : <#+ 
			    }
#>value;
<#+
				}
			else
			{
#>
				<#=code.FieldName(edmProperty)#> = value;
<#+
			}
#>

Nb: n’oubliez pas de renommer la variable edmProperty en fonction de votre template.

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Découvrez nos autres articles

Aller au contenu principal