2012-02-21 1 views
0

Dire que j'ai IQueryable<Car> cars.Valeur d'exécution différée inchangée

J'itérer ce comme:

foreach (Car c in cars) 
{ 
    c.Doors = 2; 
} 

Pourquoi c.Doors contient la valeur d'origine après la foreach, au lieu de la valeur modifiée?

Nous vous remercions à l'avance

+0

Je sais que si je le convertis en Liste avant d'énumérer, j'obtiens les bons résultats. – Dante

+0

Soit l'implémentation de IQueryable génère un nouvel ensemble à chaque itération, soit le setter de Car.Doors est 'cassé'. S'il vous plaît nous montrer où IQuerable est créé – Polity

+0

IQueryable est le résultat d'une requête Linq to Entities. Le setter est correct car dans la requête Linq, je peux assigner la valeur à la propriété Doors. – Dante

Répondre

1

Vous avez dit que IQueryable est le résultat d'une requête LINQ à des entités qui ne sont pas une déclaration correcte. MyDatabaseContext.Cars.Where (x => x.Name == "Test") renvoie un IQueryable qui, à l'itération, exécute une requête sur la base de données. (L'itération est quand vous effectuez un foreach dessus). Donc, il ne contient pas encore le jeu de résultats, juste la requête. La boucle deux fois sur les voitures génère 2 requêtes identiques à la base de données et renvoie 2 jeux de résultats identiques. Si vous voulez conserver les données. vous devez appeler ToArray ou ToList ou, après manipulation, effectuer une sauvegarde des modifications avant de recommencer.

+0

Peut-être que c'était une mauvaise formulation de ma part, mais je sais que l'IQueryable en lui-même n'exécute pas la requête. Donc, quand je l'itère, la requête est exécutée une fois. Si je fais un ToList() après l'itération, la requête sera exécutée à nouveau. Droite? – Dante

+0

Correct, ToList itère en interne la source :) – Polity

1

L'itération sur un IQueryable récupère le jeu de résultats de la base de données au fur et à mesure, comme vous le savez sûrement. Ce que j'ai observé dans cette situation et dans d'autres, c'est que ce résultat n'est pas mis en cache, donc vous trouverez souvent que l'itération sur le IQueryable réexécutera la requête, donc vos modifications ne sont pas conservées car vous obtenez un nouveau jeu de résultats qui n'a jamais été affecté par ce code. La raison pour laquelle cela fonctionne lorsque vous appelez le ToList() d'abord et que vous parcourez le résultat est que ToList() récupère et matérialise l'ensemble des résultats, qui n'est plus lié au contenu de la base de données et qui n'est en fait qu'une copie de base de données retournée. La seule façon de vous assurer que vos modifications resteront est d'opérer sur la copie locale des données, c'est-à-dire de la retirer de la zone IQueryable. Cela peut être aussi simple que d'enregistrer un IEnumerable du jeu de résultats (c'est-à-dire le résultat de ToEnumerable()), qui retournera le même jeu de résultats chaque fois que vous l'énumérerez, mais contrairement à ToList() cela ne provoquera pas d'évaluation immédiatement.