IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linq Discussion :

[LINQ-NotSupportedException] "ne prend pas en charge la traduction en SQL"


Sujet :

Linq

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    70
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2006
    Messages : 70
    Par défaut [LINQ-NotSupportedException] "ne prend pas en charge la traduction en SQL"
    Bonjour à tous,

    Débutant en LINQ, je suis en train de regarder ce que cela propose. Je développe en C# avec VS 2010 et LINQ To SQL.

    Mon problème est le suivant, lors d'une requête j'aimerai introduire une notion de Filtre afin de réduire le nombre d'enregistrements remontés. Voici comment je procède :

    coté requête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var RdvDemandeList = from rdv in this.maBase.RdvRequest
                                     where rdv.RepondFiltre(filtre)
                                     select rdv;
    Coté business, la méthode qui me renvoie un booléen:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     public bool RepondFiltre(FiltreSrvDemande filtre)
            {
    ... //Divers tests avec les paramètres de l'objet filtre
    }
    D'après les exemples que j'ai pu glaner sur le net ce genre de requête, à ma grande surprise, devrait marcher. Mais dans mon cas c'est une NotSupportedException qui est levée et qui m'indique:
    La méthode 'Boolean RepondFiltre(RDV_Manager.FiltreSrvDemande)' ne prend pas en charge la traduction en SQL.
    Ai-je donc mal compris, et ce genre de requête n'est pas possible? Ou bien qq'un voit-il où je commet une faute ou un oubli?

    Merci!

    Rastamath69

  2. #2
    Rédacteur
    Avatar de The_badger_man
    Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2005
    Messages
    2 745
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 745
    Par défaut
    de quels exemples parles-tu ?

    Quand tu écris une requete Linq to SQL, celle-ci est convertie en code SQL.
    Dans le cas de ta requete, le moteur va essayer de convertir RepondFiltre en code SQL, ce qui n'est pas possible.
    Les règles du forum
    Le trio magique : FAQ + Cours + fonction rechercher
    Mes articles
    Pas de questions par messages privés svp

    Software is never finished, only abandoned.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    70
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2006
    Messages : 70
    Par défaut
    Salut,

    Alors par exemple j'avais ce site (c'est le dernier que j'ai pu retrouver dans mes onglets) : http://code-magazine.com/Article.aspx?quickid=050133

    Il explique ceci à un moment:
    You can use all .NET expressions, objects, methods, and properties in LINQ. For instance, if you have a list of customer objects where each customer object has a method called “IsPremiumCustomer()” you could use it in the query expression:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    select customer from customer in customers
        where customer.IsPremiumCustomer()
    Ta réponse colle avec ce que je pensais, à savoir que LINQ To SQL doit savoir interpréter ce que j'écris, en SQL. Cela m'étonnais aussi, que je puisse utiliser des méthodes de mes objets métiers comme ceci, aussi facilement!!

    Sinon du coup je reste bien embêté... Fonctionnellement je m'en suis sorti en faisant mon traitement de filtre au niveau business, ce qui m'oblige à remonter les données de toute ma table via LINQ... Ceci n'est donc pas du tout une solution envisageable sur du long terme, ne serait-ce que pour des questions de performance.

    Mon filtre a des propriétés qui sont du texte, des entiers ou des datetime, sachant bien évidemment que lorsque je ne les renseigne pas (je leur ai imposé des valeurs par défaut) je ne dois pas en tenir compte.

    En gros comment faire en LINQ un truc propre qui me permettrait de répondre aux exemples suivants :

    1) si mon filtre.dateDebut est renseigné, alors la requête SQL devrait être:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Select * from maTable
    Where date > filtre.dateDebut
    2) si mon filtre.nom est renseigné, alors la requête SQL devrait être:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Select * from maTable
    Where Nom = filtre.nom
    3) si mon filtre.nom et filtre.dateDebut sont tous les deux renseignés, alors la requête SQL devrait être:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Select * from maTable
    Where Nom = filtre.nom And date > filtre.dateDebut
    Bien évidemment mon but est de ne pas faire des "if" à tour de bras pour isoler chaque cas!

    Si propositions il y a, je suis preneur!!! :-)
    Merci d'avance!

    Rastamath69

  4. #4
    Rédacteur
    Avatar de The_badger_man
    Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2005
    Messages
    2 745
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 745
    Par défaut
    Tu n'est pas obligé de faire toutes les combinaisons possibles car tu peux enchainer les Where en LINQ.
    Tu as 3 cas mais 2 if suffisent:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public IEnumerable<RdvRequest> GetRdvs(FiltreSrvDemande filtre)
    {
       var RdvDemandeList = from rdv in this.maBase.RdvRequest                                 
                                     select rdv;
     
       // dateDebut est un nullable
       if(filtre.dateDebut != null)
          RdvDemandeList  = RdvDemandeList.Where(r => r.Date > filtre.dateDebut.Value);
     
       if(string.IsNullOrEmpty(filtre.nom))
         RdvDemandeList  = RdvDemandeList.Where(r => r.Nom> filtre.nom);
     
       return RdvDemandeList.ToList();
    }
    Les règles du forum
    Le trio magique : FAQ + Cours + fonction rechercher
    Mes articles
    Pas de questions par messages privés svp

    Software is never finished, only abandoned.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    70
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2006
    Messages : 70
    Par défaut
    Au niveau performance comment cela se passe-t-il?

    Je veux dire, cette requête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     var RdvDemandeList = from rdv in this.maBase.RdvRequest                                 
                                     select rdv;
    remonte à priori tout ce que j'ai dans ma table "RdvRequest" sur mon serveur.

    Et ces deux traitements :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     if(filtre.dateDebut != null)
          RdvDemandeList  = RdvDemandeList.Where(r => r.Date > filtre.dateDebut.Value);
     
       if(string.IsNullOrEmpty(filtre.nom))
         RdvDemandeList  = RdvDemandeList.Where(r => r.Nom> filtre.nom);
    sont exécutés au niveau business et non en tant que traitement de base? C'est du LinqToObject, c'est bien ça?

    Cela ne risque-t-il pas d'impacter les performances si, par exemple ma table contenait des millions de lignes?

    Rastamath69

  6. #6
    Rédacteur
    Avatar de The_badger_man
    Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2005
    Messages
    2 745
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 745
    Par défaut
    Citation Envoyé par rastamath69 Voir le message
    Je veux dire, cette requête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     var RdvDemandeList = from rdv in this.maBase.RdvRequest                                 
                                     select rdv;
    remonte à priori tout ce que j'ai dans ma table "RdvRequest" sur mon serveur.
    non. Ici on a juste déclaré une requete. Tant qu'on n'a pas utilisé son (éventuel) résultat, son exécution n'a pas lieu.

    Citation Envoyé par rastamath69 Voir le message
    Et ces deux traitements :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     if(filtre.dateDebut != null)
          RdvDemandeList  = RdvDemandeList.Where(r => r.Date > filtre.dateDebut.Value);
     
       if(string.IsNullOrEmpty(filtre.nom))
         RdvDemandeList  = RdvDemandeList.Where(r => r.Nom> filtre.nom);
    sont exécutés au niveau business et non en tant que traitement de base? C'est du LinqToObject, c'est bien ça?
    Non. Ils permettent de compléter la construction de la requête LINQ to SQL. Rien n'a encore était envoyé à la base.


    L'exécution de la requête LINQ to SQL (transformation en SQL et envoie à la base) va se faire au moment du ToList() dans mon exemple.

    Si tu as déjà fait du SQL dynamique, on va dire que ça y ressemble. Tu construits ta requête mais tu ne l'exécutes que lorsque que tu le demandes.

    Dans mon exemple le code SQL envoyé à la base sera un select avec la clause Where correspondant aux valeurs du filtre.
    Le ToList() signifie: Ok j'ai fini de construire ma requête, génère le SQL correspondant et envoie le à la base. Ramènes moi le résultat sous forme de List d'objet de type X.

    Tu peux mettre un profiler sur la base SQL pour vérifier le code SQL envoyé si tu veux.
    Les règles du forum
    Le trio magique : FAQ + Cours + fonction rechercher
    Mes articles
    Pas de questions par messages privés svp

    Software is never finished, only abandoned.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    70
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2006
    Messages : 70
    Par défaut
    Ahhh!! Je savais pas tout ça!!

    Merci beaucoup pour toutes ces informations!!!

    Cela devient bien plus sympa d'un coup! :-)


    Dernier petit souci afin de finaliser mon filtre en LINQ, existe-t-il l'équivalent du "like" SQL en LINQ?

    Mon filtre comporte également une chaine de caractère, et cette dernière peut être de la forme : "maChaine*", et je n'ai pas trouvé comment l'exprimer?

    Rastamath69

  8. #8
    Rédacteur
    Avatar de The_badger_man
    Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2005
    Messages
    2 745
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 745
    Par défaut
    Tu peux utiliser certaines fonctions du framework que le moteur Linq to SQL est capable de transformer en SQL. Dans ton cas, la méthode Contains de la classe String. Un exemple ici:
    http://davidhayden.com/blog/dave/arc...SQLServer.aspx

    De la doc là: http://msdn.microsoft.com/en-us/library/bb386970.aspx
    Les règles du forum
    Le trio magique : FAQ + Cours + fonction rechercher
    Mes articles
    Pas de questions par messages privés svp

    Software is never finished, only abandoned.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    70
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2006
    Messages : 70
    Par défaut
    Oui j'avais déjà vu cela, et donc j'ai fait rapidement un petit truc, hier, en me servant des clauses where comme tu me l'as montré:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     if (filtre.NomApplication != String.Empty)
                {
                    ////Cas d'un filtre : *ABC
                    if (filtre.NomApplication.StartsWith("*") && !filtre.NomApplication.Substring(1).Contains("*"))
                    {
                        RdvDemandeList = RdvDemandeList.Where(r => r.NomApplicationEmettrice.ToLower().EndsWith(filtre.NomApplication.Substring(1).ToLower()));
                    }
                    ////Cas d'un filtre ABC*
                    else if (filtre.NomApplication.EndsWith("*") && !filtre.NomApplication.Substring(0, filtre.NomApplication.Length - 1).Contains("*"))
                    {
                        RdvDemandeList = RdvDemandeList.Where(r => r.NomApplicationEmettrice.ToLower().StartsWith(filtre.NomApplication.Substring(0, filtre.NomApplication.Length - 1).ToLower()));
                    }
                    ////Cas d'un filtre ABC
                    else if (!filtre.NomApplication.Contains("*"))
                    {
                        RdvDemandeList = RdvDemandeList.Where(r => r.NomApplicationEmettrice.ToLower().CompareTo(filtre.NomApplication.ToLower()) == 0);
                    }
                    //else
                    //{
                    //    //caractère joker non conforme, Cas non traité pour le moment
                    //    return false;
                    //}
                }
    Mais il se trouve que si on venait à me mettre des filtres plus complexe du genre AB*C ou encore A*B*CD*E, là ça devient rapidement embêtant à gérer!
    Je m'explique : même si je découpe ma chaine avec un Split(new char[]{'*'}) et que je fais un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Boolean resultat = true;
    String[] monTab = monFiltre.NomApplication.Split(new char[] { '*' });
    foreach(String str in monTab)
         resultat &= maChaineAtester.Contains(str);
    cela ne fera que tester leur présence, mais cela ne tiendra pas compte de l'ordre, à savoir que A soit avant B, B avant C et après A,...
    Le "like" et le "%" en sql savent gérer cela. Donc à part s'il existe une méthode sur les String qui fasse cela et que je ne connaisse pas, j'en déduis que je n'ai pas de vrai équivalent à "LIKE" en LINQ alors?

    Rastamath69

Discussions similaires

  1. Réponses: 2
    Dernier message: 31/07/2011, 20h04
  2. ne prend pas en charge la traduction en SQL
    Par sidee dans le forum Linq
    Réponses: 2
    Dernier message: 20/09/2010, 12h53
  3. Réponses: 10
    Dernier message: 15/10/2008, 16h47
  4. Réponses: 8
    Dernier message: 20/06/2006, 16h54
  5. Réponses: 27
    Dernier message: 19/10/2005, 10h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo