Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Entity Framework et la compatibilité arrière (problème Datetime2).

[new:05/07/2010]Vous possédez un OS récent, comme Windows 7, vous développez avec les outils les plus modernes (disons VS 2010 au hasard) et, bien entendu votre base de données installée en local est SQL Server 2008. D’une part parce que c’est une bonne version, mais surtout parce que vous n’avez pas trop le choix… Vous créez une application pour un client qui utilise SQL Server 2005 et là, pof! dès qu’il exécute votre logiciel il y a une exception du genre “The version of SQL Server in use does not support datatype 'datetime2”…

Vous cherchez alors comme un fou dans votre code, dans les méta données de la base où vous avez bien pu utiliser le type “datetime2”. Mais rien. Que pouic. Néant.

La base de données n’utilise que des types SQL 2005, elle-même est bien une base SQL 2005, quand au code, vous en être certain, jamais aucune référence à Datetime2 nulle part.

Quel est ce mystère ?

Il se cache dans l’Entity Framework. Lorsque vous avez créé le modèle vous étiez connecté à votre serveur SQL Server 2008, peu importe que la base de données soit une base SQL 2005 ou non. C’est le serveur qui compte.

Or, le designer de l’Entity Framework optimise le modèle selon la version du serveur. C’est à dire que voyant que votre serveur est SQL 2008, il a stocké des informations permettant d’optimiser les requêtes pour cette version là.

De fait, lorsque le logiciel est lancé, chez vous, ça passe impeccable… Mais chez le client ça bug. EF fabrique des requêtes et des classes à la volée, et il utilise notamment le type DateTime2 de SQL Server 2008 qu’il juge plus efficace que le type DateTime de la version précédente. Mais comme SQL Server 2005 ne sait pas traiter ce type là, forcément ça coince.

La solution

Une fois qu’on sait c’est très simple.

Il suffit de charger le fichier .edmx (le modèle EF) dans un éditeur XML (ou le bloc-notes au pire) et de repérer en début de fichier généralement la balise suivante :

   1: <Schema Namespace="Syo_DataModel.Store" Alias="Self" 
   2:   Provider="System.Data.SqlClient" ProviderManifestToken="2008" 
   3:   xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">

Comme vous le constater elle contient un attribut “ProviderManifestToken” qui, pour l’heure, indique la valeur “2008”.

C’est simple : changer cette valeur en “2005” et dès lors le modèle sera “optimisé” pour SQL Server 2005. Cela continue de fonctionner sous SQL Server 2008 (si la base elle même est bien au format 2005).

Conclusion

Une solution très simple pour une erreur qui peut prendre la tête. A noter dans vos tablettes donc !

Et Stay Tuned !

Faites des heureux, PARTAGEZ l'article !

Commentaires (12) -

  • Rakoun

    21/07/2010 22:21:45 | Répondre

    Ah merci mille fois pour cette information, j'étais sur le point d'installer une instance SQL Server 2005.

    Rakoun
    /°\

  • Olivier

    23/07/2010 19:23:42 | Répondre

    @Rakoun : content de t'avoir gagner le temps que j'ai perdu avant trouver l'astuce Smile

  • Victor

    10/03/2011 10:33:39 | Répondre

    Merci !
    J'ai eu peur de devoir cassé mon model pour le rebasé sur une instance SQL2005

    So happy !

    Et en anglais, pas beaucoup de site propose la solution.

    Encore merci Olivier !

  • Olivier

    10/03/2011 18:44:25 | Répondre

    @Victor: c'est une astuce peu connue, pourtant elle évite en effet des heures de galère ! (et réinstaller un serveur 2005 n'est pas toujours possible sur les versions récentes de Windows). Happy coding !

  • Seb

    20/04/2011 18:54:30 | Répondre

    Pour compléter cet intéressant article, j'ai une petite information sur un autre problème de DateTime entre SQL Server et Entity Framework.

    Sous VS 2010 + SQL 2008 mon DBA à l'habitude d'utiliser des DateTime dont certains peuvent être automatiquement initialisés par la base de données.

    Mais, avec Entity Framework, lors de l'insertion d'un nouvel enregistrement les dates dont la propriété Nullable = false sont initialisées à 01/01/0001 00:00:00 par EF et la valeur par défaut côté SQL Server n'est pas appliquée (By Design ^^).

    Comme un DateTime ne peut pas être inférieur au 01/01/1753 (basée sur le calendrier Grégorien), SQL Server interprète automatiquement la date 01/01/0001 00:00:00 en tant que DateTime2 et
    essaie de la convertir en DateTime au moment de l'insertion ce qui génère l'exception :
    {"La conversion d'un type de données datetime2 en type de données DateTime a créé une valeur hors limites.\r\nL'instruction a été arrêtée."}

    La seule solution est d'initialiser les champs DateTime avec une valeur supérieure au 01/01/1753 avant d'appeler ObjectContext.SaveChanges().

  • Olivier

    20/04/2011 20:57:26 | Répondre

    @Seb: Merci de ce rappel sur cet autre problème des DateTime.

    Je ne l'ai que rarement rencontré car en général j'utilise une couche objet métier qui initialise par défaut les valeurs du type "créé le" ou "dernière modification le" par exemple. Et ce, peu importe les inits de la base de données. C'est une sécurité, les objets métiers devant se protéger même si les règles de la base de données changent (volontairement ou par erreur).

    Mais le cas peut se produire quand on utilise d'autres architectures et il est bien utile de garder en mémoire l'astuce du billet et ta très juste remarque sur cet autre problème des DateTime !

  • Christophe "BJ"

    22/06/2011 18:36:26 | Répondre

    Merci beaucoup pour cette astuce ! ! ! !
    Elle vient de m'éviter certainement beaucoup de temps perdu ! ! !
    Merci

  • Vivien

    31/08/2011 14:12:21 | Répondre

    Merci Olivier !

    Tu viens de me faire gagner beaucoup de temps Smile

  • Christophe

    28/10/2011 15:19:00 | Répondre

    Merci beaucoup à Olivier et Seb. Les 2 astuces m'ont bien aidé.

  • Bogdanov

    20/12/2011 15:26:27 | Répondre

    Si il y avait "+1" je l'aurais fait ...

  • ADIBA

    11/11/2012 13:33:53 | Répondre

    Merci Beaucoup j'étais près à obliger les clients à utiliser sql server 2008 loooool

Ajouter un commentaire