2016-04-16 2 views
1

Im utilisant NHibernate4 et Oracle 12. NHibernate configuré pour utiliser Oracle10gDialect.NHibernate - Sélectionner les enregistrements par date du serveur

Premier code associé.

public class WorkOrder 
{ 
    ........ 
    public virtual DateTime CreationDate {get; set;} 
    ........ 
} 

CreationDate mappée comme:

Map(x => x.CreationDate)  
    .Column("CREATION_DATE") 
    .CustomType("DateTime") 
    .Access.Property() 
    .Generated.Never() 
    .CustomSqlType("DATE") 
    .Not.Nullable(); 

échantillons de requête:

var workOrders1 = session.Query<WorkOrders>() 
     .Where(p => DateTime.Today.Date.Equals(p.CreationDate.Date)) 
     .ToList(); 

var workOrders2 = session.Query<WorkOrders>() 
     .Where(p => p.CreationDate.Date == DateTime.Today.Date) 
     .ToList(); 

    var workOrders3 = session.Query<WorkOrders>() 
     .Where(p => p.CreationDate.Date.Equals(DateTime.Today.Date)) 
     .ToList(); 

Toutes les requêtes LINQ ci-dessus converties en sql comme ceci:

select workorders0_.CREATION_DATE as CREATION11_ 
from APPS.WORK_ORDERS workorders0_ 
where TIMESTAMP '2016-04-16 00:00:00' /* :p0 */ = trunc(workorders0_.CREATION_DATE) 

Ces requêtes utilise les ordinateurs clients l'heure du système (et en tant que paramètre), pas le temps système des serveurs. Je préfère toujours utiliser l'heure du serveur. Pour la base de données oracle sur laquelle je travaille, je préfère "sysdate" car le champ "CreationDate" est défini par by avant le déclencheur d'insertion en utilisant la fonction "sysdate".

NHibernate peut-il utiliser le datetime du serveur directement? et le paramètre n'est pas requis. Comme:

select workorders0_.CREATION_DATE as CREATION11_ 
from APPS.WORK_ORDERS workorders0_ 
where trunc(sysdate) = trunc(workorders0_.CREATION_DATE) 

En résumé, la partie "où" doit être changée du premier au second. la version NHibernate est v4.0.30319

where TIMESTAMP '2016-04-16 00:00:00' /* :p0 */ = trunc(workorders0_.CREATION_DATE) 
where trunc(sysdate) = trunc(workorders0_.CREATION_DATE) 

Répondre

2

Je pense que vous devez étendre pour supporter cela. (Même DateTime.Now ne se traduit pas à un équivalent SQL.)

La meilleure façon devrait être l'ajout du support pour la fonction SQL supplémentaire demonstrated by this blog, si votre Oracle sysdate peut être gérée en fonction. (Avec SQL Server, il est sysdatetime(), et il peut être manipulé dans linq2NH en tant que fonction.)

Mais malheureusement, il y a une grande limitation dans le courant : seul l'appel de méthode sur les entités ou les propriétés d'entité peut être traduit en SQL . Tout autre appel sera évalué à l'exécution .Net, comme expliqué here.

Pour surmonter cela, nous devons ajouter un paramètre factice à notre appel de fonction. Voici ce que je l'ai fait dans SQL-Serveur:

create function dbo.customGetDate (@dummy sql_variant = null) 
returns datetime2 as 
begin 
    return sysdatetime() 
end 
using NHibernate.Linq; 

... 

public static class CustomLinqExtensions 
{ 
    [LinqExtensionMethod("dbo.customGetDate")] 
    public static DateTime GetSysDate(this object dummy) 
    { 
     // No need to implement it in .Net, unless you wish to call it 
     // outside IQueryable context too. 
     throw new NotImplementedException(); 
    } 
} 

alors vous pourrez écrire:

var workOrders1 = session.Query<WorkOrders>() 
    .Where(p => p.GetSysDate().Date == p.CreationDate.Date) 
    .ToList(); 

Si vous voulez éviter de déclarer une fonction personnalisée dans db, vous devriez alors étendre linq2NH d'une manière plus difficile, comme ajouter votre propre "LinqToHqlGenerator" comme dans mon self-answer here. Mais vous devrez toujours appeler votre extension sur une entité, ou des propriétés d'entité.

C'est moche, mais je ne trouve pas de meilleur moyen.

+0

Merci beaucoup. Mais je reçois Une exception non gérée de type 'System.NotSupportedException' s'est produite dans NHibernate.dll Informations supplémentaires: PartialEvalException (NotImplementedException ("La méthode ou l'opération n'est pas implémentée."), PartialEvalException (NotImplementedException (" La méthode ou l'opération n'est pas implémentée. "), GetSysDate()). Date) J'ai recherché cette méthode et cela doit fonctionner.J'ai fait des tests avec différents oracledialects rien changé – ayocak

+0

mes propres tests, et oui, son apparence cet attribut d'extension ne supporte pas les fonctions sans paramètre ... Assez malheureux.Je peux appeler n'importe quelle fonction ayant des paramètres, y compris ceux définis par l'utilisateur (y compris leur schéma dans leur nom). en ajoutant une fonction définie par l'utilisateur ayant un paramètre fictif qui appelle le paramètre less function.Je suis toujours à la recherche d'une meilleure solution.Il semble qu'il doit être appelé sur une propriété d'entité mappée.C'est une grande limitation.O –

+0

Je n'ai rien trouvé de mieux J'ai mis à jour ma réponse en conséquence –