72 votes

Le résultat d'une requête ne peut pas être énuméré plus d'une fois

Je suis en train d'utiliser le framework d'entités (ef) et je reçois l'erreur suivante :

"Le résultat d'une requête ne peut être énuméré plus d'une fois.".

J'ai une classe repository qui contient le contexte de données ef. Ensuite, j'ai une classe contrôleur (à ne pas confondre avec les contrôleurs MVC) qui contient une instance du repository. Jusqu'ici tout va bien... J'ai une méthode de recherche sur le contrôleur qui est censée renvoyer un tableau de RadComboBoxItemData, qui est utilisé pour peupler un contrôle Telerik RadComboBox.

public RadComboBoxItemData[] Search(int id, string searchText)
{
    var query = context.Search(id, searchText);
    List result = new List();
    foreach (var item in query)
    {
        RadComboBoxItemData itemData = new RadComboBoxItemData();
        itemData.Text = ""; // assign some text here..;
        itemData.Value = ""; /*assign some value here..*/
        result.Add(itemData);
    }

    return result.ToArray();
}

Lorsque je débogue mon code, je peux entrer dans la boucle foreach, mais ensuite je reçois une erreur disant :

Une exception de type 'System.InvalidOperationException' s'est produite dans System.Data.Entity.dll mais n'a pas été gérée dans le code utilisateur

Informations supplémentaires : Le résultat de une requête ne peut être énuméré plus de une fois.

Mon entité utilise une importation de fonction d'une procédure stockée existante.

// Méthode du repository EF appelant la méthode importée de fonction sur le contexte de données.
public IEnumerable Search(int id, string searchText)
{
    return this.entityContext.Search(id, searchText);
}

L'importation de fonction Search appelle une procédure stockée pour renvoyer une collection de SearchItem.

J'ai l'impression que la boucle foreach ne peut pas itérer en raison de quelque chose avec le ef.

4 votes

Tu manques de .ToList(), je ne vois juste pas où... Je vais prendre un café et y jeter un autre coup d'œil

153voto

Yakimych Points 9312

Essayez d'énumérer explicitement les résultats en appelant ToList().

Changer

foreach (var item in query)

à

foreach (var item in query.ToList())

5 votes

@Halcyon cela fonctionne parce qu'en utilisant ToList vous récupérez TOUS les résultats de la base de données dans cette liste, à partir de maintenant les méthodes linq ne vont plus fonctionner sur la base de données. Cela peut poser un problème sérieux de performance en fonction de la quantité de données que vous avez et de ce que vous en ferez.

4 votes

@BrunoLM - Dans ce cas, l'OP itère déjà à travers TOUS les résultats de la requête. Au cas où d'autres "méthodes linq" doivent être exécutées contre la base de données, il peut continuer à utiliser la variable query. Non seulement je ne vois aucun problème avec la solution, mais c'est aussi la meilleure façon possible de résoudre le problème de l'OP. Pouvez-vous expliquer le vote négatif?

15 votes

La raison .ToList() fonctionne est que lorsque vous utilisez un IEnumerable, la collection est itérée de manière paresseuse. Dans ce cas, chaque fois que la boucle foreach récupère un élément, la requête récupère l'élément depuis votre base de données ou autre source, si vous voulez itérer à nouveau, elle ne pourra pas refaire la requête. Lorsque vous utilisez .ToList(), tous les éléments dans l'IEnumerable sont traités et sauvegardés dans une liste. Ensuite, vous pouvez utiliser la liste créée autant de fois que vous le souhaitez.

11voto

hosam hemaily Points 285

Essayez de remplacer ceci

var query = context.Search(id, searchText);

avec

var query = context.Search(id, searchText).tolist();

et tout fonctionnera bien.

0 votes

Tolist() rend l'entité libre, si vous n'utilisez pas tolist, il est prévu que l'entité ne soit pas libérée et que vous travailliez dessus

-1voto

Dani Points 624

Code problématique appelant une procédure stockée :

var resultSP = db.StoredProcedure(id);

if (resultSP != null)
{
    var count = resultSP.Count();

    var list = resultSP.Select(x=>...);
}

Corrigé, stocker dans une variable avec ToList() et le réutiliser :

var resultSP = db.StoredProcedure(id);

if (resultSP != null)
{
    var resultSP_List = resultSP.ToList();

    var count = resultSP_List.Count();

    var list = resultSP_List.Select(x=>...);
}

0 votes

C'est exactement ce que la réponse acceptée a dit. Veuillez ne pas répéter les réponses.

0 votes

Ce n'est pas exactement ce que la réponse acceptée a dit, si vous utilisez 2 tolist dans la même requête, l'erreur persiste @GertArnold, la réponse ne dit pas que vous devez enregistrer la liste et réutiliser la variable

0 votes

OK, mais alors cela duplique cette réponse.

-5voto

rishi kaithwas Points 1

Si vous obtenez ce type d'erreur, je vous suggère d'utiliser une procédure stockée pour stocker les données sous forme de liste habituelle, puis de lier les autres contrôles, car j'ai également rencontré cette erreur et je l'ai résolue comme ceci ex: -

repeater.DataSource = data.SPBinsReport().Tolist();
repeater.DataBind();

essayez comme ceci

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