Question

J'essaie de refacter une couche de données LINQ à SQL encombrante avec une entité Framework. Le schéma de la base de données derrière le modèle est grand et une requête typique peut avoir 20 à 30 incluse. L'EF génère des instructions SQL massives pour de telles requêtes, la plus grande jusqu'à présent a été des lignes de 4K, mais elles s'exécutent toujours en temps opportun, ce qui n'est pas un problème.

Le problème est que l'EF prend beaucoup de temps, jusqu'à 4 ou 5 secondes pour générer la requête. Pour surmonter, j'ai utilisé CompileQuery. Le problème est alors que le Datalayer L2S existant a beaucoup de filtres qui peuvent être appliqués à une requête en fonction de l'entrée utilisateur. Une seule valeur dans ces filtres doit être définie au moment de l'exécution.

Le code ci-dessous ne fonctionne pas car les valeurs statiques initiales sont compilées dans la requête, mais il démontre ce que j'essaie de faire.

public static class DataLayer
{
    static Func<MyEntities, int, IQueryable<Prescription>> compiledQuery;

    static int? FilterHpID;
    static Expression<Func<Prescription, bool>> filter1 = x => (FilterHpID == null || x.Prescriber.HPID == FilterHpID);

    static DateTime? FilterDateTime;
    static Expression<Func<Prescription, bool>> filter2 = x => (FilterDateTime == null || x.DateTimeDispensed > FilterDateTime);

    public static List<Prescription> Get(int patientID, int? hpID, DateTime? dispensed)
    {
        FilterHpID = hpID;
        FilterDateTime = dispensed;

        if (compiledQuery == null)
        {
            compiledQuery = System.Data.Objects.CompiledQuery.Compile((MyEntities entities, int id) =>
                        (from pre in entities.Prescription
                         where pre.PatientID == id
                         select pre)
                         .Where(filter1)
                         .Where(filter2));
        }

        using (MyEntities entities = new MyEntities())
        {
            return compiledQuery(entities, patientID).ToList();
        }
    }
}

Y a-t-il un moyen de pouvoir inclure mes expressions de filtre dans la requête compilée et être en mesure de définir des valeurs sur les expressions de filtre lors de l'exécution de la requête?

Était-ce utile?

La solution 2

Après avoir cherché élevé et faible, la conclusion à laquelle je suis arrivée est qu'il n'y a aucun moyen de pouvoir utiliser des expressions réutilisables dans une requête compilée et encore moins d'expressions nécessitant un paramètre.

L'intention du code ci-dessous n'est possible en aucune forme ou en aucune manière.

static Expression<Func<Prescription, bool>> filter1 = x => (FilterHpID == null || x.Prescriber.HPID == 1);

compiledQuery = System.Data.Objects.CompiledQuery.Compile((MyEntities entities, int id) =>
                    (from pre in entities.Prescription
                     where pre.PatientID == id
                     select pre)
                     .Where(filter1));

Nous allons partir et regarder l'utilisation des vues de base de données comme un moyen de contourner la nécessité d'utiliser des requêtes compilées en premier lieu. Si les requêtes L2E n'ont pas besoin d'être compilées pour éviter de prendre un délai de près de 2 secondes, des filtres d'expression réutilisables peuvent être ajoutés.

Autres conseils

Les filtres doivent faire partie de la requête compilée et, après cela, vous pouvez les définir lorsque vous appelez la requête. Je pense que vous pouvez utiliser quelque chose comme:

public static IQueryable<Prescription> Filter1(this IQueryale<Prescription> query, 
    DateTime? param)
{
    return query.Where(x => (param == null || x.Prescriber.HPID == param));
}

Ensuite, vous devriez pouvoir définir votre requête compilée comme:

 compiledQuery = System.Data.Objects.CompiledQuery
                       .Compile((MyEntities entities, int id, DateTime? param) =>
                           (from pre in entities.Prescription
                            where pre.PatientID == id
                            select pre)
                           .Filter1(param));

Cela fonctionne avec des requêtes normales, mais je ne l'ai jamais essayé dans des requêtes compilées. Si cela ne fonctionne pas, vous devez placer l'expression du filtre directement dans la requête compilée:

 compiledQuery = System.Data.Objects.CompiledQuery
                       .Compile((MyEntities entities, int id, DateTime? param) =>
                           (from pre in entities.Prescription
                            where pre.PatientID == id
                            select pre)
                           .Where(x => (param == null || x.Prescriber.HPID == param));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top