Question

Considère ma classe Event et que je stocke les DateTime dans la base de données en tant que dates UTC. Je veux simplement renvoyer une plage filtrée basée sur la date du jour dans un fuseau horaire particulier - easy right?

Cela fonctionne bien:

IQueryable<Event> test1 = this.GetSortedEvents().Where(e => e.FinishDateTime.Date >= DateTime.UtcNow.Date);

Cela fonctionne aussi très bien:

IQueryable<Event> test2 = this.GetSortedEvents().Where(e => e.FinishDateTime.AddHours(3).Date >= DateTime.UtcNow.AddHours(3).Date);

.. et répond également aux exigences de mon fuseau horaire.

Donc, je pense pouvoir déplacer cette conversion spécifique vers cette méthode d'extension:

    public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
    {
        return utcTime.AddHours(3);
    }

Cela ne marche PAS:

IQueryable<Event> test3 = this.GetSortedEvents().Where(e => e.FinishDateTime.RiyadhTimeFromUtc().Date >= DateTime.UtcNow.RiyadhTimeFromUtc().Date);

.. et j'obtiens cette exception NotSupportedException: La méthode 'System.DateTime RiyadhTimeFromUtc (System.DateTime)' n'a pas de traduction prise en charge en SQL.

C’est évidemment une saleté, car le compilateur l’a heureusement converti en SQL quand le code identique n’était PAS dans la méthode d’extension.

J'ai rencontré le " ne possède pas de traduction SQL prise en charge " problème avant avec certains types et le plus récemment DateTime. Mais mes tests ci-dessus et ce lien prouvent que la méthode AddHours doit être pris en charge dans la traduction SQL.

Si quelqu'un pouvait me dire ce que je faisais mal ici (ou une approche différente de ce problème), je vous en serais très reconnaissant.

Était-ce utile?

La solution

Vous devez y penser en termes d'arborescence d'expression. C'est ainsi que Linq-to-SQL analyse votre requête pour la transformer en SQL.

Lors de l’examen de l’arborescence, un objet DateTime sera détecté, puis le logiciel vérifiera si la méthode appelée est une des méthodes prises en charge ( Add , AddHours , etc.) donc lorsque vous utilisez la méthode directement, cela fonctionne bien.

Lorsque vous utilisez une autre méthode d'extension, elle ne peut pas aller voir à l'intérieur de cette méthode pour voir ce qu'elle fait, car les informations sur le corps de cette méthode ne sont pas dans l'arbre des expressions, elles sont cachées dans l'IL. Donc, peu importe que le contenu de la méthode d'extension soit pris en charge, car Linq-to-SQL ne peut pas déterminer le contenu.

L'intérêt de créer des méthodes est l'encapsulation et le masquage d'informations, ce qui fonctionne généralement bien dans le développement d'applications, mais malheureusement, il masque ici les informations fournies à Linq-to-SQL, qui doit pouvoir les afficher.

En réponse à la question modifiée - comment résolvez-vous cela? Si vous souhaitez conserver le calcul de la date dans l'expression Linq, la seule chose à faire pour optimiser l'efficacité de la requête est de ne pas utiliser de méthode d'extension. Vous devez simplement utiliser AddHours (3) directement sur < code> objet DateTime .

C’est l’une des limitations malheureuses de Linq. Comme beaucoup de choses, il s’agit d’une abstraction quelque peu fugace qui, tout en fournissant une syntaxe commune sur plusieurs sources, présente différentes limitations et restrictions quant aux opérations que le fournisseur de la source peut / va prendre en charge (par exemple, cela fonctionnerait parfaitement dans Linq-to -Objets car il n'a pas besoin de traduire l'arborescence d'expression pour l'exécuter).

Autres conseils

Il semble que LINQ-to-SQL puisse comprendre que RiyadhTimeFromUtc n’est en réalité qu’un appel à AddHours (3) , il faudrait en faire analyse assez sophistiquée de votre code. Dites que vous avez écrit:

public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
{
    if (Random.GetInt() < 99) {
       return utcTime.AddHours(3);
    } else {
       return utcTime.AddDays(5);
    }
}

Comment cela se traduirait-il en SQL? Voir cette discussion pour plus d’informations.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top