2010-01-14 32 views
11

Ich versuche, eine alte rohe SQL-Abfrage in Linq mit Entity Framework hier zu konvertieren."IN" Operator in Linq

Es wurde mit dem IN-Operator mit einer Sammlung von Artikeln. Die Anfrage war so etwas wie die:

SELECT Members.Name 
FROM Members 
WHERE Members.ID IN (SELECT DISTINCT ManufacturerID FROM Products WHERE Active = 1) 
ORDER BY Members.Name ASC 

Da die Rückkehr der Unterabfrage nicht eine einzelne Zeichenfolge, sondern eine Sammlung von Strings kann ich nicht die String.Contains() Methode verwenden.

Ich dachte darüber nach, wie etwas zu tun:

var activeProducts = (
from products in db.ProductSet 
where product.Active == true 
select product.ManufacturerID); 

und dann

var activeMembers = (
from member in db.ContactSet 
where member.ID.ToString().Contains(activeProducts)); 

aber es hält an der hinweist, dass das ungültige Argumente hat ... Ich kann nicht wählen, weil activeProducts.ManufacturerID offensichtlich die proprety nicht da ist, da es eine IQueryable gibt ...

Unterm Strich, was ich versuche, hier zu tun ist, eine Liste der Mitglieder zurück, die mindestens eine haben aktives Produkt.

Irgendwelche Hinweise?

[Bearbeiten]

Hier ist die vollständige Abfrage-Code ... Ich habe versucht, mit der enthält auf dem zweiten Ausdruck, Linq schien es nicht zu mögen:

Server Error in '/' Application. LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Linq.IQueryable``1[System.String], System.String)' method, and this method cannot be translated into a store expression.

var activeProduct =(from product in Master.DataContext.ProductSet 
         where product.Active == true 
          && product.ShowOnWebSite == true 
          && product.AvailableDate <= DateTime.Today 
          && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
         select product.ManufacturerID.ToString()); 

    var activeArtists = from artist in Master.DataContext.ContactSet 
         where activeProduct.Contains(artist.ID.ToString()) 
         select artist; 

    NumberOfArtists = activeArtists.Count(); 

    artistsRepeater.DataSource = activeArtists; 
    artistsRepeater.DataBind(); 

[Mehr Details] ManufacturerID ist eine Nullwert-GUID, anscheinend ...

Aus irgendeinem Grund enthält die ContactSet-Klasse kein a Wenn ich mich auf die Produkte beziehe, werde ich wohl eine Join-Abfrage machen müssen, keine Hinweise hier.

Antwort

12
var activeMembers = (
from member in db.ContactSet 
where activeProducts.Select(x=>x.ID).Contains(member.ID)); 
5

Versuchen where activeProducts.Contains(member.ID).
EDIT: Haben Sie es ohne ToString s versuchen?

+0

Funktioniert nicht, habe einen Linq-Fehler. – Erick

+0

Yup, und Linq mag es immer noch nicht, ich habe gerade entdeckt, dass ManufacturerID ein Guid ist? (NULL-Wert) ... wenn ich eine 'HerstellerID auswählen wähle.Wert "Ich habe Folgendes: LINQ to Entities erkennt die Methode 'Boolean Enthält [Guid] (System.Linq.IQueryable'1 [System.Guid], System.Guid)' nicht, und diese Methode kann nicht in einen Informationsspeicher übersetzt werden Ausdruck. – Erick

+0

Ist das so effizient wie der IN-Operator? – tofutim

0

Statt dessen:

var activeMembers = (
from member in db.ContactSet 
where member.ID.ToString().Contains(activeProducts)); 

Versuchen Sie folgendes:

var activeMembers = (
from member in db.ContactSet 
where activeProducts.Contains(member.ID)); 
+0

Versucht, Linq schien es nicht wirklich zu mögen. – Erick

+0

Was genau ist passiert, als du es versucht hast? – SLaks

+0

Der Fehler ist dort oben in der Bearbeitung =) – Erick

0

Was passiert, wenn Sie die Anweisung (ungetestet) tauschen?

where activeProducts.Contains(member.ID) 
0

Wie wäre es damit ...

var activeProducts = (
from products in db.ProductSet 
where product.Active == true 
select product.ManufacturerID); 

var activeMembers = (
from member in db.ContactSet 
where activeProducts.Contains(member.ID.ToString())); 
+0

Funktioniert nicht wirklich. – Erick

+0

ich diese Änderung denke, es wäre ... var activeProducts = funktioniert ( von Produkten in db.ProductSet wo product.Active == true product.ManufacturerID wählen); var activeMembers = ( von Mitglied in db.ContactSet wo activeProducts.Select (x => x.id) .Contains (member.ID.ToString())); – spadelives

+0

'product.Active == true' ist ein bisschen überflüssig, nicht wahr? Nur 'product.Active' ist genug. – Askolein

2

Sie es in einer Abfrage tun:

var q = from member in db.ContactSet 
     where member.Products.Any(p => p.IsActive) 
     select member; 
+0

Ich musste die Aussage vereinfachen, aber es gibt mehr Bedingungen für das "wo" ... Ich habe meinen Beitrag bearbeitet, um den vollständigen Code in die Tat aufzunehmen. – Erick

+1

Sie können es immer noch in einer Abfrage tun. Verschieben Sie die gesamte Where-Klausel in den Any-Aufruf. – SLaks

+0

Es gibt keine Verbindung von ContactSet zu ProductSet appendly (oh, wie ich 3rd-Party-Software-Modifikation liebe), ich denke, ich werde eine Join-Abfrage machen müssen ... – Erick

0

Ein Helfer oder Extension-Methode wird gut funktionieren, wenn sie gegen Objekte im Speicher abfragt. Aber gegen eine SQL-Datenbank wird Ihr LINQ-Code in einen Ausdrucksbaum kompiliert, analysiert und in einen SQL-Befehl übersetzt. Diese Funktionalität hat kein Konzept von benutzerdefinierten Erweiterungsmethoden oder Methoden anderer Objekte wie .Contains(...).

Es könnte jedoch leicht in die Standard-LINQ-To-SQL-Funktionalität von Microsoft implementiert werden. Aber solange sie nicht wollen, sind wir hilflos, solange es keine Open-Source-Funktionalität ist.

Sie können nur Ihren eigenen QueryProvider erstellen, der gegen eine SQL-Datenbank arbeitet. Aber es wird schwer sein und es wäre nur für diese eine in Feature, die Sie vermissen.

Allerdings, wenn Sie wirklich wollen diesen Weg zu gehen, Spaß haben: LINQ: BUILDING AN IQUERYABLE PROVIDER SERIES

0

Schließlich gelang es mir, etwas wirklich hässlich zu kodieren, aber das funktioniert tatsächlich! (Lol)

var activeProduct =(from product in Master.DataContext.ProductSet 
         where product.Active == true 
          && product.ShowOnWebSite == true 
          && product.AvailableDate <= DateTime.Today 
          && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
         select product.ManufacturerID).Distinct(); 

    var artists = from artist in Master.DataContext.ContactSet 
         select artist; 

    List<Evolution.API.Contact> activeArtists = new List<Evolution.API.Contact>(); 

    foreach (var artist in artists) 
    { 
     foreach(var product in activeProduct) 
     { 
      if (product.HasValue && product.Value == artist.ID) 
       activeArtists.Add(artist); 
     } 
    } 

    NumberOfArtists = activeArtists.Count(); 

    artistsRepeater.DataSource = activeArtists; 
    artistsRepeater.DataBind(); 
0
var q = (from p in db.DOCAuditTrails 
     where p.ActionUser == "MyUserID" 
     && p.ActionTaken == "Not Actioned" 
     && p.ActionDate > DateTime.Parse("2011-09-13") 
      select p.RequisitionId).Distinct(); 

var DocAuditResults = db.DOCAuditTrails.Where(p 
    => q.ToArray().Contains(p.RequisitionId)); 
1

Was dazu:

from m in members 
where products.FirstOrDefault(prod => prod.IsActive == 1 && prod.Id == m.Id) != null 
select m; 

können Sie Kette eine beliebige Anzahl von Bedingungen erforderlich in der Klausel, wo mit & &

Ash ..

2
from m in members 
where products.Any(p => p.Active && p.ManufacturerID == m.ID) 
select m 

oder

from m in members 
join p in products on m.ID equals p.ManufacturerID 
where p.Active 
select m 
0

wissen Ohne die genaue Zuordnungen es schwer zu sagen ist, was getan werden kann und was nicht. Ich gehe davon aus, dass kein Casting involviert ist. Zuerst müssen Sie daran denken, dass alles in der Linq Ausdrucksbaumstruktur eine Entsprechung in SQL haben muss. Wie einige andere bemerkt haben, haben Sie ein Objekt.ToString() in Ihren Linq-Anweisungen.

Es scheint jedoch, dass, was die Menschen zu erwähnen vernachlässigt haben, dass Sie zwei Verwendungen von object.ToSting() haben, die beide entfernt werden müssen.

Ich würde auch eine zusätzliche Variable machen, um den Capture-Typ des Closures explizit von DataContext zu ändern (da die Linq-Anweisung wie ein Lambda und verzögert ausgewertet wird. Es muss die gesamte Master-Variable nehmen stellte fest, dass alles in Ihrem Linq eine Entsprechung in SQL haben muss. Da Master möglicherweise nicht in SQL existieren kann, gibt es keine DataContext-Eigenschaft/Spalte/Zuordnung für den Typ von Master.

var context = Master.DataContext; 
var activeProduct = from product in context.ProductSet 
        where product.Active == true 
         && product.ShowOnWebSite == true 
         && product.AvailableDate <= DateTime.Today 
         && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
        select product.ManufacturerID; 

var activeArtists = from artist in context.ContactSet 
        where activeProduct.Contains(artist.ID) 
        select artist; 

Ich hoffe, dass die oben genannten Änderungen für Sie arbeiten. In vielen Fällen können Probleme mit Linq zu ORMs auf Ihren Linq-Ausdruck zurückgeführt werden, der eine nicht primative (DateTime, int, string usw.) und nicht ORM-basierte Klasse (DataContext/EntityObject usw.) erfasst. Die andere wichtige Frage ist die Verwendung von Funktionen und Operatoren, die nicht durch das ORM offen gelegt werden (es ist möglich, benutzerdefinierte Funktionen durch das ORM der .net-Funktion zuzuordnen, aber ich würde es aufgrund von Indizierungsproblemen nicht empfehlen).