2012-03-14 1 views
1

J'ai actuellement cette requête Linq:Comment Linq-ify cette requête?

return this.Context.StockTakeFacts 
       .OrderByDescending(stf => stf.StockTakeId) 
       .Where(stf => stf.FactKindId == ((int)kind)) 
       .Take(topCount) 
       .ToList<IStockTakeFact>(); 

L'intention est de retourner tous les faits pour la topCount de StockTakes mais je peux voir que je n'obtenir le numéro de topCount des faits.

Comment linq-ify cette requête pour atteindre mon objectif?

Je pourrais utiliser 2 requêtes pour obtenir le top-topCountStakeId, puis faire un "entre" mais je me demandais quelles astuces Linq pourrait avoir.

C'est ce que j'essaie de battre. Notez qu'il s'agit vraiment plus d'apprendre que de ne pas être capable de trouver une solution. Aussi préoccupé par la performance pas pour ces questions, mais en général, je ne veux pas juste des choses faciles et découvre qu'il se débat dans les coulisses. Comme quelle est la pénalité de cette clause contient dans ma deuxième requête ci-dessous?

List<long> stids = this.Context.StockTakes 
       .OrderByDescending(st => st.StockTakeId) 
       .Take(topCount) 
       .Select(st => st.StockTakeId) 
       .ToList<long>(); 

      return this.Context.StockTakeFacts 
       .Where(stf => (stf.FactKindId == ((int)kind)) && (stids.Contains(stf.StockTakeId))) 
       .ToList<IStockTakeFact>(); 
+3

Que voulez-vous dire Linqify? Il est déjà linq – manojlds

+0

@manojlds. Je suppose que _ "Linqify" _ fait fonctionner linq, bien que je n'ai pas vérifié le dictionnaire ... =) – gdoron

+0

pourquoi ne pas SELECT fait, et appliquer Take (topCount) à StockTake. Vous devrez joindre les tables dans le champ Id. – Doomsknight

Répondre

0

Que pensez-vous de cela?

return this.Context.StockTakeFacts 
       .OrderByDescending(stf => stf.StockTakeId) 
       .Where(stf => stf.FactKindId == ((int)kind)) 
       .Take(topCount) 
       .Select(stf=>stf.Fact) 
       .ToList(); 
+0

Salut.Non, malheureusement, il ne saisit pas tous les stocktakefacts pour les meilleurs stocktakes. Il saisit le top n stocktakefacts. – rism

0

Si je comprends ce que vous êtes après correctement, que diriez-vous:

return this.Context.StockTakes 
    .OrderByDescending(st => st.StockTakeId) 
    .Take(topCount) 
    .Join(
     this.Context.StockTakeFacts, 
     st => st.StockTakeId, 
     stf => stf.StockTakeId, 
     (st, stf) => stf) 
    .OrderByDescending(stf => stf.StockTakeId) 
    .ToList<IStockTakeFact>(); 
0

Voici ma tentative en utilisant la plupart du temps la syntaxe de requête et en utilisant deux requêtes distinctes:

var stids = 
    from st in this.Context.StockTakes 
    orderby st.StockTakeId descending 
    select st.StockTakeId; 

var topFacts = 
    from stid in stids.Take(topCount) 
    join stf in this.Context.StockTakeFacts 
    on stid equals stf.StockTakeId 
    where stf.FactKindId == (int)kind 
    select stf; 

return topFacts.ToList<IStockTakeFact>(); 

Comme d'autres ont suggéré, ce que vous cherchiez est une jointure. Parce que l'extension join a tellement de paramètres qu'ils peuvent être un peu déroutants - donc je préfère la syntaxe de la requête lorsque je fais des jointures - le compilateur donne des erreurs si l'ordre est incorrect, par exemple. Join est de loin préférable à un filtre, non seulement parce qu'il décrit la manière dont les données sont jointes, mais aussi pour des raisons de performance car il utilise des index lorsqu'il est utilisé dans une base de données et des hachages lorsqu'il est utilisé dans linq to objects.

Vous devez noter que j'appelle le Take dans la deuxième requête pour limiter aux valeurs topCount utilisées dans la deuxième requête. Au lieu d'avoir deux requêtes, j'aurais pu utiliser un into (suite, poursuite de requête) sur la ligne de sélection de la requête stids pour combiner les deux requêtes, mais cela aurait créé un désordre pour le limiter à topCount éléments. Une autre option aurait été de mettre la requête stids entre parenthèses et d'appeler Take dessus. Au lieu de cela, le séparer en deux requêtes semblait le plus propre à moi.

J'évite généralement de spécifier des types génériques quand je pense que le compilateur peut déduire le type; cependant, IStockTakeFact est presque certainement une interface et quel que soit le type concret implémente il est probablement contenu par this.Context.StockTakeFacts; qui crée le besoin de spécifier le type générique sur l'appel ToList. Ordinairement, j'omets le paramètre de type générique à mes appels ToList - cela semble être un élément de mes goûts personnels, le vôtre peut différer. Si this.Context.StockTakeFacts est déjà List<IStockTakeFact>, vous pouvez omettre le type générique lors de l'appel ToList.