2012-05-30 3 views
1

J'ai une ligne de code LINQ qui déclenche une exception System.NotSupportedException.Pourquoi la version LINQ de cette boucle foreach lance-t-elle une exception NotSupportedException ("NotSupportedException")?

 return unconvertedUrls 
        .Select(potentialQueryURL => ConvertPotentialQueryURLToSeed(potentialQueryURL)) 
        .Where(id => id > 0) 
        .ToList(); 

Le message d'exception est " 'Int32 ConvertPotentialQueryURLToSeed (de SeedsSQLConnector.PotentialQueryURL)' Méthode n'a pas de traduction pris en charge à SQL"

Cependant, la simple conversion à une boucle de foreach fonctionne sans problème.

 var result = new List<int>(); 
     foreach (var potentialQueryURL in unconvertedUrls) 
     { 
      var id = ConvertPotentialQueryURLToSeed(potentialQueryURL); 
      if (id > 0) 
      { 
       result.Add(id); 
      } 
     } 
     return result; 

Qu'est-ce qui ne va pas et pourquoi?

========== ========== EDIT

Odd, un collègue a proposé une autre solution qui fonctionne aussi. Il semble que le LINQ transmettait ConvertPotentialQueryURLToSeed à la base de données! Quoi qu'il en soit, voici l'autre solution, qui consiste à ajouter .ToList() à la déclaration précédente:

 var unconvertedUrls = (from url in _DataContext.PotentialQueryURLs 
           where !convertedUrlIds.Contains(url.Id) 
           select url).ToList(); 
     return unconvertedUrls 
        .Select(potentialQueryURL => ConvertPotentialQueryURLToSeed(potentialQueryURL)) 
        .Where(id => id > 0) 
        .ToList(); 
+0

Je suppose que vous utilisez EF ou NHibernate, le problème est que l'ORM ne peut pas traduire ce que vous avez entré dans SQL. Que fait votre fonction? Peux-tu nous le montrer? Votre deuxième exemple fonctionne car vous n'interrogez pas la base de données. – mattytommo

Répondre

3

La raison est que LINQ to SQL n'exécute pas que le code de la requête, mais tente de le convertir en un SQL déclaration. Comme il ne sait pas ConvertPotentialQueryURLToSeed cette conversion échoue.

Le foreach fonctionne car, dans ce cas, la méthode ConvertPotentialQueryURLToSeed n'est pas utilisée dans la partie de la requête LINQ qui est en cours de traduction vers SQL.

La version avec ToList fonctionne pour la même raison: ToList récupère les données de la requête si loin de la base de données. À partir de ce moment, vous travaillez sur des objets C# normaux, appelés LINQ to Objects.

+0

Merci Daniel, je vais marquer ceci comme la réponse dans six minutes. Existe-t-il un moyen de dire à LINQ que la fonction est une fonction locale et non une base de données? Ajouter ToList() à l'instruction précédente semble le faire (voir edit to question) mais y a-t-il un moyen plus lisible? – dumbledad

+0

@dumbledad Votre modification fonctionne parce que vous avez résolu la liste en utilisant 'ToList' et effectivement effectué LINQ sur une collection en mémoire dans la deuxième instruction, de sorte que la deuxième instruction n'appelle pas la base de données. – mattytommo

+1

@dumbledad: Non, il n'y a pas d'autre moyen. –

Questions connexes