2009-08-21 7 views
0

J'ai eu le code Linq suivant:Comment utiliser Count et Group dans une requête de sélection dans Linq?

var allRequests = model.GetAllRequests(); 

    var unsatisifedRequests = (from request in allRequests 
           where request.Satisfied == false 
           select request) 
           .OrderBy(r => r.RequestedOn) 
           .GroupBy(r => r.RequestedCountryId); 

Après que je puis fait un foreach sur unsatifiedRequests la construction d'un nouvel objet TOARequestListSummary pour chacun. Cela signifiait que si je "renvoyais" 4 éléments de la requête, cela ferait 4 appels au DB, une fois par boucle du foreach pour saisir les lignes individuelles.

Cela semble être la mauvaise façon d'utiliser LINQ, donc je tente de convertir cette requête à l'une qui a utilisé les projections pour retourner les TOARequestListSummary objets directement et je suis venu avec:

var summaries = (from request in allRequests 
          where request.Satisfied == false 
          group request by request.RequestedCountryId into requestGroups 
          select new TOARequestListSummary 
          { 
           CountryName = requestGroups.First().RequestedCountry.Description, 
           RequestCount = requestGroups.Count(), 
           FirstRequested = requestGroups.First().RequestedOn 
          }); 

Mais quand je lance ce, je reçois l'exception suivante:

Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. 

J'ai aussi loin que de savoir que l'équivalent à Linq est EXISTE Contient, mais je ne sais pas comment cela indroducir dans la requête.

Répondre

3

Cela devrait fonctionner pour vous:

var summaries = (from request in allRequests 
       where request.Satisfied == false 
       group request by request.RequestedCountry into g 
       select new TOARequestListSummary 
       { 
        CountryName = g.Key.Description, 
        RequestCount = g.Count(), 
        FirstRequested = g.Min(i => i.RequestedOn) 
       }); 

Dans votre version originale de cette requête (le second vous avez publié), la clé de votre groupe était le RequestedCountryId. Bien que cela soit techniquement regrouper sur cela, vous voulez réellement utiliser l'objet associé. De cette façon, vous aurez facilement accès aux propriétés nécessaires et vous n'aurez pas à vous soucier de saisir le premier élément.

+0

En fait, ce n'est pas tout à fait correct. Dans mon exemple, 'RequestedOn' est supposé être sur l'objet' RequestedCountry', alors que yours l'a sur 'request' lui-même. Y a-t-il une certaine manière que vous voulez déterminer le 'FirstRequested'? Si ce n'est pas le cas, vous pouvez utiliser 'requestGroups.First(). RequestedOn' comme vous l'avez dit plus haut. Si vous voulez le plus petit ou le plus grand (ou d'une autre manière), je peux faire des changements pour le corriger. –

+0

RequestedOn est une colonne DateTime et j'essayais de les faire commander afin que ceux demandés en premier étaient en haut de la liste. Lorsque j'ai essayé le code dans votre réponse, il semble que g est une collection de Country obejcts (le type de RequestedCountry) donc .Requested sur ne compile pas. Lorsque j'ai essayé g.First(). Demandé, j'obtiens l'excpetion suivante: Le membre 'Logica.Aurora.Data.Entities.TOARequest.RequestedCountry' n'a aucune traduction prise en charge par SQL. Ce qui, je présume, signifie qu'il ne peut pas être groupé? –

+0

Est-ce que 'RequestedCountry' est une propriété LinqToSql générée automatiquement à partir de vos relations de base de données? Donc, 'FirstRequested' devrait-il être le plus ancien' request' pour ce groupe, ou devrait-il être la date de la plus ancienne 'request'? –

0

Désolé, cela est une réponse, plutôt que d'un commentaire supplémentaire à la réponse de Ryan, mais il est trop long pour ...

Cela devient très étrange. Dans LINQPad les travaux suivants un régal:

from request in TOARequests 
where request.Satisfied == false 
&& request.Active == true 
orderby request.RequestedOn 
group request by request.RequestedCountry into g 
select new 
{ 
    CountryName = g.Key.Description, 
    RequestCount = g.Count(), 
    FirstRequested = g.First().RequestedOn 
} 

Mais ce qui suit jette la même exception de la traduction en C#

var summaries = (from request in context.Repository<TOARequest>() 
          where request.Satisfied == false 
          && request.Active == true 
          orderby request.RequestedOn 
          group request by request.RequestedCountry into g 
          select new 
          { 
           CountryName = g.Key.Description, 
           RequestCount = g.Count(), 
           FirstRequested = g.First().RequestedOn 
          }).ToList(); 

La seule différence que je peux voir si le ToList(), mais même sans cela quand je essayer d'énumérer la liste, il jette l'exception.

+1

Vous voudrez probablement utiliser 'FirstRequested = g.Min (i => i.RequestedOn)' et vous débarrasser de l'orderby (comme je l'ai fait dans ma récente édition). Je ne sais toujours pas pourquoi vous obtenez cette exception de traduction Sql, car cela devrait fonctionner correctement (comme indiqué dans LinqPad). –

+0

Merci, le Min fonctionne très bien. Je ne sais pas pourquoi cela ne fonctionne pas dans le code, car cela fonctionne très bien dans LinqPad. Merci pour votre temps. –

+0

J'ai marqué votre réponse précédente comme correcte car cela fonctionne dans LinqPad, il doit y avoir quelque chose d'étrange avec mon code. –

Questions connexes