2009-05-22 7 views
19

Ich habe die folgenden drei Tabellen als Teil eines einfachen "Artikel Tagging" Schema:Linq-Version von SQL "IN" Anweisung

== == Artikel

  • ItemId int
  • Marke varchar
  • Namen varchar
  • Preisgeld
  • Zustand varchar
  • Beschr iption varchar
  • Aktiv Bit

== == Stichworte

  • TagId int
  • Namen varchar
  • Aktiv Bit

== == TagMap

  • TagMapId int
  • TagId int (fk)
  • ItemId int (fk)
  • Aktiv Bit

Ich möchte eine LINQ-Abfrage schreiben Artikel zurück zu bringen, die eine Liste von Tags entsprechen (z TagId = 2,3,4,7). In meinem Anwendungskontext wären Beispiele für Gegenstände "Computer Monitor", "Smoking Shirt", "Gitarre" usw. und Beispiele für Tags wären "Elektronik", "Kleidung" usw. Ich würde dies normalerweise mit einem SQL erreichen IN-Anweisung.

+0

Warum die innere join ist hier nicht bevorzugt? Sie wissen, wenn die Context.TagMaps 10 Datensätze enthält, wird es 36-mal im Hintergrund iterieren, unabhängig davon, ob es eine Übereinstimmung gibt oder nicht. – Pankaj

+2

Sie können [SQL-Abfragen in LINQ] (http://www.codeducky.org/sql-queries-in-linq/#where-in) hilfreich finden. Es ist eine Liste der häufigsten SQL-Abfragen in LINQ. –

Antwort

42

So etwas wie

var TagIds = new int[] {12, 32, 42}; 

var q = from map in Context.TagMaps 
     where TagIds.Contains(map.TagId) 
     select map.Items; 

tun sollten, was Sie brauchen. Dies erzeugt eine In (12, 32, 42) -Klausel (oder genauer gesagt eine parametrisierte IN-Klausel, wenn ich mich nicht irre).

+0

kommt es durch die ausgewählte map.Item Teil ins Spiel. In SQL müssten Sie die TagMap mit der Item-Tabelle verbinden. Linq macht das für Sie wegen der Beziehung von TagMap zu Item. Sie sagen im Wesentlichen: "Finden Sie alle TagMaps, die auf eines meiner TagIds verweisen, und geben Sie mir ihr Element zurück". Diese Linq-Abfrage ist die gleiche wie die folgende SQL:. SELECT Items * VON TagMaps INNER JOIN Elemente auf Item.ItemId = TagMap.ItemId WHERE TagMaps.TagId IN (12,32,24) Linq nimmt Pflege des INNER JOIN-Teils für dich, weil er weiß, wie man von TagMap zu Item gelangt. –

+0

Warum wird die innere Verbindung hier nicht bevorzugt? Sie wissen, wenn die "Context.TagMaps" 10 Datensätze enthält, wird es 36 Mal im Hintergrund iterieren, unabhängig davon, ob es eine Übereinstimmung gibt oder nicht. – Pankaj

+0

Die Array-Deklaration ist nicht ganz richtig. Kombiniere diese Antwort mit @ LukeSchäfers Antwort unten und es wird funktionieren. – boilers222

14

gegeben Array von Elementen:

var list = new int[] {2,3,4} 

Verwendung:

where list.Contains(tm.TagId) 
+0

Ich verstehe nicht, wie das bei dem 3-Tabellenschema funktionieren würde, das ich habe. –

1
List<int> tagIds = new List<int>() {2, 3, 4, 7}; 
int tagIdCount = tagIds.Count; 
    // 
// Items that have any of the tags 
// (any item may have any of the tags, not necessarily all of them 
    // 
var ItemsAnyTags = db.Items 
    .Where(item => item.TagMaps 
    .Any(tm => tagIds.Contains(tm.TagId)) 
); 

    // 
// Items that have ALL of the tags 
// (any item may have extra tags that are not mentioned). 
    // 
var ItemIdsForAllTags = db.TagMap 
    .Where(tm => tagIds.Contains(tm.TagId)) 
    .GroupBy(tm => tm.ItemId) 
    .Where(g => g.Count() == tagIdCount) 
    .Select(g => g.Key); 
    // 
var ItemsWithAllTags = db.Items 
    .Where(item => ItemsIdsForAllTags.Contains(item.ItemId)); 

//runs just one query against the database 
List<Item> result = ItemsWithAllTags.ToList(); 
1

Sie können einfach verwenden,

var TagIds = {12, 32, 42} 
var prod =entities.TagMaps.Where(tagmaps=> TagIds .Contains(tagmaps.TagId)); 
0
string[] names = {"John", "Cassandra", "Sarah"}; 

var results = (from n in db.Names 
       where names.Contains(n.Name) 
       select n).ToList();