2 votes

Requête Xlinq renvoyant null WhereEnumerableIterator<>

J'essaie de faire une requête xlinq filtrante en c# 4.0, afin de pouvoir lier un DataContext. le code est le suivant

public IEnumerable<XElement> Filter(int min = 0, int max = int.MaxValue)
{
    IEnumerable<XElement> selected = (
        from x in xmlFile.Elements("Product")
        where (int)x.Element("Price") >= min &&
              (int)x.Element("Price") <= max
        select x);

    return selected;
}

xmlFile est un XElement avec un fichier xml externe chargé. La structure du fichier xml ressemble à ceci :

<Stock>
    <Product>
      <Name /> 
      <Price /> 
      <Quantity /> 
    </Product>
    ...
</Stock>

Je n'obtiens aucune erreur lors de la construction ou de l'exécution, mais le fichier selected n'obtient que null (même sans la clause where). Lorsque je passe la souris sur la variable lors du débogage, elle affiche le type System.Linq.Enumerable.WhereEnumerableIterator. Si je renvoie simplement le fichier xmlFile, tout se passe bien, mais j'ai vraiment besoin de faire le filtrage !


EDIT

D'après mes recherches, le problème se situe au niveau de l'instruction "xmlFile.Elements("Product")". Je ne sais pas comment l'expliquer, alors j'ai fait une capture d'écran (dans mon code, j'utilise en fait "Respuesto" à la place de "Products", je l'ai traduit ici pour que ce soit plus facile) :

(Je ne peux pas insérer d'image car je suis un nouvel utilisateur, mais elle est ici : http://i.stack.imgur.com/XTt8r.png

J'utilise cette fonction dans mon code en tant que DataContext comme suit :

gridpricelist.DataContext = Conn.Filter(min: Convert.ToInt32(minprice.Text),
                            max: Convert.ToInt32(maxprice.Text));

minprice et maxprice sont des zones de texte, et un événement KeyUp déclenche la fonction ci-dessus


EDIT2

J'ai trouvé la solution, voir ma réponse. Mais je n'arrive pas à expliquer pourquoi cela fonctionne ainsi, quelqu'un pourrait-il m'aider à comprendre ?

Merci d'avance !

2voto

xanatos Points 30513

Si vous avez des éléments de prix "vides" ou "non existants", cela ne fonctionnera pas.

Essayez ceci :

public static IEnumerable<XElement> Filter(int min = 0, int max = int.MaxValue)
{
    Func<XElement, int?> parse = p => {
        var element = p.Element("Price");

        if (element == null) {
            return null;
        }

        int value;

        if (!Int32.TryParse(element.Value, out value)) {
            return null;
        }

        return value;
    };

    IEnumerable<XElement> selected = (
        from x in xmlFile.Elements("Product")
        let value = parse(x)
        where value >= min &&
            value <= max
        select x);

    return arr;
}

1voto

tinchou Points 334

J'ai trouvé la solution ! Bien que je ne sache pas pourquoi l'approche Xlinq ne fonctionne pas... voici le code qui a fonctionné pour moi à la place de la requête :

    public XElement filter(int min = 0, int max = int.MaxValue)
    {            
        XElement filtered = new XElement("Stock");
        foreach (XElement product in xmlFile.Elements("Product"))
        {
            if ((int)product.Element("Price") >= min &&
                (int)product.Element("Price") <= max)
                    filtered.Add(product);
        }
        return filtered;
    }

Je vous remercie de votre attention et de votre compréhension.

0voto

user7116 Points 39829

Vous avez deux problèmes :

  1. Lorsque vous passez la souris sur le WhereEnumerableIterator et a vu .Current était null Tout fonctionnait normalement. Il s'agit de exécution différée au travail. Certaines requêtes LINQ (cela s'applique également à XLinq) ne s'exécutent pas tant que vous ne les avez pas énumérées, d'où le fait que .Current sera null jusqu'à ce que vous l'utilisiez ! Lorsque vous avez utilisé foreach dans votre réponse, il énumère l'itérateur et produit une valeur.

  2. Votre code initial n'a pas fonctionné car il a renvoyé une énumération de XML sans élément racine, et il semble que votre code d'appel, quel qu'il soit, exige qu'il ait une racine. Votre réponse enveloppe les données dans un élément <Stock> élément. Vous pouvez utiliser votre code original comme suit :

    public XElement Filter(int min = 0, int max = int.MaxValue)
    {
        var selected = (
            from x in xmlFile.Elements("Product")
            where (int)x.Element("Price") >= min &&
                  (int)x.Element("Price") <= max
            select x);
    
        return new XElement("Stock", selected);
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X