2012-04-02 13 views
24

Ich möchte in meine Tabelle eine Spalte mit dem Namen 'S' einfügen, die basierend auf einem Wert, den sie aus einer Tabellenspalte erhält, einen Zeichenfolgewert erhält.Aufruf einer Methode innerhalb einer Linq-Abfrage

Zum Beispiel: for each ID (a.z) Ich möchte es String Wert in einer anderen Tabelle gespeichert erhalten. Der Zeichenfolgenwert wird von einer anderen Methode zurückgegeben, die ihn über eine Linq-Abfrage erhält.

  • Ist es möglich, eine Methode von Linq aufzurufen?
  • Sollte ich alles in der gleichen Abfrage tun?

Dies ist die Struktur der Informationen, die ich erhalten müssen:

a.z is the ID in the first square in table #1, from this ID I get another id in table #2, and from that I can get my string value that I need to display under column 'S'.
enter image description here

var q = (from a in v.A join b in v.B 
    on a.i equals b.j 
    where a.k == "aaa" && a.h == 0 
    select new {T = a.i, S = someMethod(a.z).ToString()}) 
    return q; 

Die Linie S = someMethod(a.z).ToString() den folgenden Fehler verursacht:

Unable to cast object of type 'System.Data.Linq.SqlClient.SqlColumn' to type 'System.Data.Linq.SqlClient.SqlMethodCall'.

+0

Ihre Frage ziemlich unklar ist (für mich jedenfalls) - Welche Tabellen sind Sie auf ? Ist das Linq zu Entitäten oder Linq zu Objekten? Sinnvollere Eigenschaften und Tabellennamen könnten ebenfalls hilfreich sein. – BrokenGlass

+0

Sorry, ich bin neu bei Linq, was meinst du mit Linq zu Entitäten oder Linq zu Objekten? – user990635

+0

Ihre Fehlermeldung zeigt an, dass Sie Linq zu SQL verwenden - so greifen Sie auf die Datenbank zu – BrokenGlass

Antwort

41

Sie haben Ihre Methodenaufruf in Linq-to-Objects Kontext zu halten, weil auf der Datenbankseite, dass die Call-Methode wird nicht Sinn machen - Sie können dies AsEnumerable() tun mit - im Grunde der Rest der Abfrage wird dann als eine im Speicher Sammlung ausgewertet werden Linq-to-Objects verwenden und Sie können verwenden Methodenaufrufe wie erwartet:

var q = (from a in v.A join b in v.B 
     on a.i equals b.j 
     where a.k == "aaa" && a.h == 0 
     select new {T = a.i, Z = a.z }) 
     .AsEnumerable() 
     .Select(x => new { T = x.T, S = someMethod(x.Z).ToString() }) 
+0

Große Antwort, Danke – EgyEast

+0

Ich möchte nur sicherstellen, dass es die Enumerable zweimal iteriert, nicht wahr? Erstens, vor der '.AsEnumerable()' und zweitens nach '.AsEnumerable()'? –

8

Sie werden es teilen möchten in zwei Aussagen. Geben Sie die Ergebnisse aus der Abfrage zurück (was die Datenbank trifft), und listen Sie die Ergebnisse ein zweites Mal in einem separaten Schritt auf, um die Übersetzung in die neue Objektliste umzuwandeln. Diese zweite "Abfrage" trifft die Datenbank nicht, so dass Sie die someMethod() darin verwenden können.

Linq-to-Entities ist ein bisschen seltsam, weil es den Übergang zur Abfrage der Datenbank von C# extrem nahtlos macht: aber Sie müssen sich immer daran erinnern, "Dieses C# wird in etwas SQL übersetzt werden . " Und als Ergebnis müssen Sie sich fragen: "Können alle diese C# tatsächlich als SQL ausgeführt werden?" Wenn es nicht möglich ist - wenn Sie someMethod() darin aufrufen - wird Ihre Abfrage Probleme haben. Und die übliche Lösung ist es, sie aufzuteilen.

(Die andere Antwort von @BrokenGlass, mit .AsEnumerable(), ist im Grunde eine andere Art und Weise, genau das zu tun.)

0

, die eine alte Frage, aber Ich sehe niemand einen "Hack" erwähnen, der es erlaubt zu cal l Methoden während der Auswahl ohne Wiederholung. Idee ist, Konstruktor zu verwenden und in Konstruktor können Sie nennen, was Sie wünschen (zumindest funktioniert es gut in LINQ mit NHibernate, nicht sicher über LINQ2SQL oder EF, aber ich denke, es sollte das gleiche sein). Unten habe ich Quellcode für Benchmark-Programm, es sieht aus wie Wiederholung Ansatz in meinem Fall ist etwa zweimal langsamer als Konstruktor Ansatz und ich denke, es ist kein Wunder - meine Geschäftslogik war minimal, so Dinge wie Iteration und Speicherzuweisung Angelegenheiten.

Auch wollte ich dort war besser Weise zu sagen, dass dieses oder jenes nicht auf Datenbank auszuführen versucht werden,

// Here are the results of selecting sum of 1 million ints on my machine: 
// Name Iterations  Percent  
// reiterate  294  53.3575317604356%  
// constructor  551  100% 

public class A 
{ 
    public A() 
    {    
    } 

    public A(int b, int c) 
    { 
     Result = Sum(b, c); 
    } 

    public int Result { get; set; } 

    public static int Sum(int source1, int source2) 
    { 
     return source1 + source2; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var range = Enumerable.Range(1, 1000000).ToList(); 

     BenchmarkIt.Benchmark.This("reiterate",() => 
      { 
       var tst = range 
        .Select(x => new { b = x, c = x }) 
        .AsEnumerable() 
        .Select(x => new A 
        { 
         Result = A.Sum(x.b, x.c) 
        }) 
        .ToList(); 
      }) 
      .Against.This("constructor",() => 
      { 
       var tst = range 
        .Select(x => new A(x, x)) 
        .ToList(); 
      }) 
      .For(60) 
      .Seconds() 
      .PrintComparison(); 

     Console.ReadKey(); 
    } 
} 
Verwandte Themen