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

C# Discussion :

Retourner une requête LINQ


Sujet :

C#

  1. #1
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Points : 63
    Points
    63
    Par défaut Retourner une requête LINQ
    Bonjour,

    Ma question va peut-être vous paraître étrange.

    Je réalise des requêtes LINQ dans mes fichiers Models. Lorsqu'il s'agit de retourner une liste de valeur il m'est facile de l'utiliser dans le ViewModel.

    Ma question est la suivante, est-il possible de retourner une requête LINQ afin de la parcourir dans mon ViewModel ? (ou ne faut-il jamais faire ça ?)

    exemple (Dans mon Model) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public IEnumerable getData_NomPoste(string ligne)
            {
                _xelement = XElement.Load(_DB_Poste_File);
     
                var queryResult = from data in _xelement.Descendants("Ligne")
                                  where (string)data.Attribute("Nom") == ligne
                                  from data_2 in data.Descendants("Poste")
                                  select data_2;
     
                return queryResult;
            }
    Dans mon ViewModel je pourrai faire :
    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
    private List<Poste> getData_NomPoste()
            {
                Poste posteObject = new Poste();
                List<Poste> posteListe = new List<Poste>();
     
                foreach (var res in posteObject.getData_NomPoste(SelectionTeamLineViewModel._ligneChoix))
                {
                    posteListe.Add(new Poste()
                    {
                        Nom = res.Element("Nom").Value
                        ID = res.Element("ID").Value,
                    });
                }
                return posteListe;
            }
    Peut-être qu'il s'agit d'une mauvaise idée de ma part ...

  2. #2
    Expert confirmé

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 066
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 066
    Points : 4 233
    Points
    4 233
    Par défaut
    Bein je vois pas en quoi c'est dérangeant surtout que c'est une liste de résultat que tu retournes et non une requête linq.

  3. #3
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Citation Envoyé par youtpout978 Voir le message
    Bein je vois pas en quoi c'est dérangeant surtout que c'est une liste de résultat que tu retournes et non une requête linq.
    Effectivement.

    C'est moi qui avait mal typé ma fonction.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public IEnumerable<XElement> getData_NomPoste(string ligne)
            {
                List<string> strListe = new List<string>();
                _xelement = XElement.Load(_DB_Poste_File);
    
                var queryResult = from data in _xelement.Descendants("Ligne")
                                  where (string)data.Attribute("Nom") == ligne
                                  from data_2 in data.Descendants("Poste")
                                  select data_2;
    
                return queryResult;
            }

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    une requête linq n'est pas évaluée tant qu'elle n'est pas lue
    retourner une requete linq dans un ienumerable ou un ienumerable<T> fait donc que c'est la requête qui est retournée

    démonstration :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    var l = new list<int>();
    l.add(5);
    l.add(8);
    var query = l.where(nb=>nb == 5); // contiendrait donc un élément
    // ici ca serait le moment où l'on pourrait return query
    l.clear();
    var finalresult = query.Count(); // finalresult vaut 0 car actuellement il n'y a aucun élément donc aucun qui correspond au where
    donc c'est au développeur de faire le choix s'il veut retourner la requête ou son contenu
    pour créer le contenu un .ToList() permet de "figer" le résultat, que le retour soit un ienumerable ou non

    quand on a des objets à ouvrir et à fermer il vaut mieux figer le résultat pour pouvoir fermer, si toutes les variables nécessaires sont en quelques sortes transmises avec
    c'est d'ailleurs une source de bug dans divers cas où une variable est utilisée dans une boucle par exemple
    d'ailleurs visual studio le précise, quand on fait une boucle for i et que i sert dans du linq, il préconise de recréer une variable pour stocker i, sinon i change et le résultat du linq avec ! (alors qu'avec une variable en plus, il y a une variable pour chaque tour de boucle, et chaque requete linq créée

    dans le doute il vaut mieux faire un return query.tolist()
    retourner query peut avoir une utilité si l'appelant fait un autre traitement filtrant par exemple, ce qui peut éviter une nouvelle itération


    au passage le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    List<Poste> posteListe = new List<Poste>();
     
                foreach (var res in posteObject.getData_NomPoste(SelectionTeamLineViewModel._ligneChoix))
                {
                    posteListe.Add(new Poste()
                    {
                        Nom = res.Element("Nom").Value
                        ID = res.Element("ID").Value,
                    });
                }
                return posteListe;
    est équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    return posteObject.getData_NomPoste(SelectionTeamLineViewModel._ligneChoix).Select(res => new Poste()
                    {
                        Nom = res.Element("Nom").Value
                        ID = res.Element("ID").Value,
                    }).ToList();
    là d'ailleurs, si getData_NomPoste est une requête linq ca évite une itération, alors que si c'est un list comme je le conseillais quelques lignes plus haut le .select va faire un for each
    après c'est pas ca qui va influencer les perfs de manière visible

  5. #5
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Merci Pol63 pour ces explications, c'est très clair

    Dans les deux formulations de code, quelle est la méthode à privilégier (synthase query ou méthode) et pourquoi ?

  6. #6
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 905
    Points : 1 923
    Points
    1 923
    Par défaut
    Citation Envoyé par youtpout978 Voir le message
    Bein je vois pas en quoi c'est dérangeant surtout que c'est une liste de résultat que tu retournes et non une requête linq.
    Comme l'a dit Pol63 ce n'est pas une liste de résultat mais bien une requête Linq qui est renvoyée, puisqu'elle n'a pas été exécutée dans la méthode ; d'ailleurs la variable queryResult aurait du s'appeler query puisqu'on en récupère pas encore le résultat, pour cela il aurait fallu utiliser ToArray(), ToList() ou bien un foreach, par exemple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public IEnumerable getData_NomPoste(string ligne)
            {
                _xelement = XElement.Load(_DB_Poste_File);
     
                var query = from data in _xelement.Descendants("Ligne")
                                  where (string)data.Attribute("Nom") == ligne
                                  from data_2 in data.Descendants("Poste")
                                  select data_2;
               var queryResult = query.ToArray();
     
                return queryResult;
            }
    Je plussoie également sur la gestion du cycle de vie des ressources et c'est particulièrement crucial pour les ressources "disposables" comme les flux de fichier ou les connexions de base de données et encore plus avec des méthodes asynchrones. Ici ça ne se voit pas car le XElement renvoyé par XElement.Load() et sur lequel est exécuté la requête est un objet "définitif" mais si on récupérait des données directement à partir d'un Stream instancié dans la méthode avec un using pour le disposer il faudrait être sûr de récupérer un résultat à renvoyer et car une requête qui serait exécutée par la suite échouerait (fluxde données fermé).

    Mais pour répondre plus spécifiquement à la question d'origine je ne vois pas de problème à renvoyer une requête Linq. D'ailleurs si on renvoie une requête on peut spécifier le type de retour IQueryable, afin de bénéficier des services plus étendu que ceux de IEnumerable (IQueryable étend IEnumerable) et afin de laisser moins d’ambiguïté sur l'objet fourni. Ça permet également de créer des éléments de requête intermédiaires à combiner avec d'autres requêtes.

    Il y a par contre d'autres éléments qui me laissent perplexe. Par exemple cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _xelement = XElement.Load(_DB_Poste_File);
    Manifestement _xelement est un champ privé de la classe ; mais pour quoi faire ? Sa valeur sera réécrite à chaque appel de getData_NomPoste() alors à quoi cela te sert-t-il de la conserver ? L'utilises-t autre part dans le code que l'on a pas ? Au passage tu ne respectes pas les conventions de nommage en C#, elle devrait s'appeler GetDataNomPoste().

    Autre chose :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Poste posteObject = new Poste();
                List<Poste> posteListe = new List<Poste>();
     
                foreach (var res in posteObject.getData_NomPoste(SelectionTeamLineViewModel._ligneChoix))
    puis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    posteListe.Add(new Poste()
                    {
                        Nom = res.Element("Nom").Value
                        ID = res.Element("ID").Value,
                    });
    Je ne veux pas trop m'avancer car je ne sais pas si c'est un code hypothétique ou si c'est ce que tu as déjà écrit, mais pour m'expliquer : dans la deuxième partie on voit que Poste est un objet de données (avec un nom, un id...). Or juste avant tu fais new Poste().getData_NomPoste(...) ce qui est quand même assez cracra ; ces deux intentions (data object et service) ne sont pas cohérentes. J'aurais pu le comprendre si l'objet lui-même était également une source de données (ex. un poste avec des sous-éléments) mais ici il s'agit d'autre chose, il n'y a même pas de configuration spécifique sur le poste. Au plus simple tu peux en faire une méthode static, que tu utiliserais directement à partir de la classe : Poste.getData_NomPoste(...). Sinon il te manque peut-être une classe qui aurait ce rôle de fournisseur de données.

  7. #7
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Bonjour Noxen,

    Manifestement _xelement est un champ privé de la classe ; mais pour quoi faire ? Sa valeur sera réécrite à chaque appel de getData_NomPoste() alors à quoi cela te sert-t-il de la conserver ? L'utilises-t autre part dans le code que l'on a pas ?
    Effectivement, _xelement est un champs privé. C'est un objet que j'appelle avant chaque query des que je crée une fonction de recherche linq.
    Sa valeur est bien réécrite à chaque appel de "getDataNomPoste()" ou d'une autre fonction. Il n'est donc pas nécessaire de la conservé. --> corrigé.

    Voici la classe Poste pour que tu aies un aperçu.
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    public class Poste
        {
            #region Variable
            private static string _DB_Poste_File = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Data\\DB_Poste.xml";
            #endregion Variable
     
            #region Constructor
            public Poste()
            {
     
            }
            #endregion Constructor
     
            #region Properties
            public string ID { get; set; }
            public string Nom { get; set; }
            #endregion Properties
     
            #region Public Method
            public static IEnumerable<XElement> getDataPoste(string ligne)
            {
                List<string> strListe = new List<string>();
                XElement _xelement = XElement.Load(_DB_Poste_File);
     
                var query = from data in _xelement.Descendants("Ligne")
                            where (string)data.Attribute("Nom") == ligne
                            from data_2 in data.Descendants("Poste")
                            select data_2;
     
                return query;
            }
     
            public static IEnumerable<XElement> getNom(string ligne, string idPoste)
            {
                XElement _xelement = XElement.Load(_DB_Poste_File);
     
                var query = from data in _xelement.Descendants("Ligne")
                            where (string)data.Attribute("Nom").Value == ligne
                            from data_2 in data.Descendants("Poste")
                            where (string)data_2.Attribute("ID").Value == idPoste
                            select data_2;
     
                return query;
            }
    }
    J'ai bien pris en compte tes remarques pour ne pas mélanger objet et service.

    C'est là où je me pose la question concernant ta remarque, à juste titre
    Sinon il te manque peut-être une classe qui aurait ce rôle de fournisseur de données.
    J'ai dans mon application l'arborescence suivante au niveau des classes Model (.cs) et DataBase (.xml)
    Nom : ArborescencePolyvalence_1.PNG
Affichages : 166
Taille : 6,2 Ko

    Je n'ai sans doute comme il faudrait, mais j'ai fait le choix de mettre dans chaque classe Model les fonctions services me permettant de récupérer les données qui leurs sont rapportées.

    exemple :
    Poste.cs ne récupère que des données de DB_Poste.xml
    Ligne.cs ne récupère que des données de DB_Ligne.xml

    Seul Polyvalence.cs à besoin de données transverses de plusieurs DB.

    Serait-il mieux que je crée une classe Process.cs (par exemple) qui centralise toutes les fonctions qui retournes des "query" ?

    (Nous sommes plus dans l'organisation de projet que dans du code, mais si nous ne l'avons pas, il sera très compliqué de maintenir ce code si MAJ il y a)

  8. #8
    Expert confirmé

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 066
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 066
    Points : 4 233
    Points
    4 233
    Par défaut
    Un vieille article qui pour moi est toujours d'actualité : https://immobilis.developpez.com/art...p-net/#LIV-B-1

  9. #9
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Un vieille article qui pour moi est toujours d'actualité : https://immobilis.developpez.com/art...p-net/#LIV-B-1
    Article très intéressant !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Retourner un dictionnaire depuis une requête Linq
    Par youtpout978 dans le forum C#
    Réponses: 5
    Dernier message: 16/02/2012, 14h12
  2. Binding HS avec une requête LINQ retournant plusieurs tables
    Par abbepierre94 dans le forum Silverlight
    Réponses: 4
    Dernier message: 01/02/2011, 11h19
  3. Réponses: 7
    Dernier message: 06/04/2009, 16h29
  4. Colle sur un tri dans une requête linq to sql
    Par boby62423 dans le forum Linq
    Réponses: 5
    Dernier message: 18/03/2009, 10h01
  5. [DIVERS] nombre de champs que retourne une requête?
    Par krolineeee dans le forum Interfaces de programmation
    Réponses: 3
    Dernier message: 24/07/2006, 09h18

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