2010-03-28 14 views
6

Gehen Sie bei Bedarf zur "spezifischen Frage". Einige Hintergrund:Wie schreibe ich diese Linq SQL als eine dynamische Abfrage (mit Strings)?

Das Szenario: Ich habe eine Reihe von Produkten mit einem "Drilldown" -Filter (Query Object) mit DDLs gefüllt. Jede progressive DDL-Auswahl wird die Produktliste sowie die für die DDLs verfügbaren Optionen weiter einschränken. Wenn Sie beispielsweise einen Hammer ohne Werkzeuge auswählen, wird die Produktgröße so eingeschränkt, dass nur die Hammergrößen angezeigt werden.

Aktuelle Konfiguration: Ich habe ein Abfrageobjekt erstellt, es an ein Repository gesendet und jede Option einer SQL- "Tabellenwertfunktion" zugeführt, wobei Nullwerte "get all products" darstellen.

Ich halte dies für eine gute Anstrengung, aber weit von DDD akzeptabel. Ich möchte jede "Programmierung" in SQL vermeiden und hoffentlich alles mit einem Repository machen. Kommentare zu diesem Thema wären willkommen.

Spezifische Frage:

Wie würde ich diese Abfrage als Dynamic Query umschreiben? Ein Link zu etwas wie 101 Linq Examples wäre fantastisch, aber mit einem dynamischen Abfragebereich. Ich möchte wirklich dieses Feld in Anführungszeichen übergeben, für die ich eine Liste von Optionen und wie viele Produkte diese Option haben möchten.

from p in db.Products 
group p by p.ProductSize into g 
select new Category { 
     PropertyType = g.Key, 
     Count = g.Count() } 

Jede DDL-Option wird „Die Auswahl (21)“, wo die (21) ist die Menge der Produkte, die das Attribut haben. Nach Auswahl einer Option werden alle anderen verbleibenden DDLs mit den verbleibenden Optionen und Zählungen aktualisiert.

Edit: Zusätzliche Hinweise:

.OrderBy("it.City") // "it" refers to the entire record 
.GroupBy("City", "new(City)") // This produces a unique list of City 
.Select("it.Count()") //This gives a list of counts... getting closer 
.Select("key") // Selects a list of unique City 
.Select("new (key, count() as string)") // +1 to me LOL. key is a row of group 
.GroupBy("new (City, Manufacturer)", "City") // New = list of fields to group by 
.GroupBy("City", "new (Manufacturer, Size)") // Second parameter is a projection 

Product 
.Where("ProductType == @0", "Maps") 
.GroupBy("new(City)", "new (null as string)")// Projection not available later? 
.Select("new (key.City, it.count() as string)")// GroupBy new makes key an object 

Product 
.Where("ProductType == @0", "Maps") 
.GroupBy("new(City)", "new (null as string)")// Projection not available later? 
.Select("new (key.City, it as object)")// the it object is the result of GroupBy 

var a = Product 
     .Where("ProductType == @0", "Maps") 
     .GroupBy("@0", "it", "City") // This fails to group Product at all 
     .Select("new (Key, it as Product)"); // "it" is property cast though 

Was ich bisher gelernt habe, ist LinqPad ist fantastisch, aber immer noch auf eine Antwort zu suchen. Irgendwann wird sich völlig zufällige Forschung wie diese durchsetzen, denke ich. LOL.

Edit:

Jon Skeet eine fantastische Idee hatte: werfen, was ich als IGrouping<string, Product> brauchen. Danke an Jon Skeet! Sobald Sie das Objekt umgewandelt haben, können Sie die Sets aufzählen und die Ergebnisse in eine separate Liste einreihen.

+0

Sie benötigen eine ganze dynamische Abfrage? Sind nicht Ihre Filterkriterien (Where-Klausel) der einzige dynamische Aspekt? – Gabe

+0

Ich glaube, ich brauche eine volle DQ. Ohne diesen Code für jedes Feld, das gefiltert werden soll, zu duplizieren, müsste ich das GroupBy-Feld als String angeben. –

+0

Cast zu IGrouping ist nur möglich, wenn Sie das 'it' zurückgeben. Wenn du benutzt .Wähle ("new (Key, it as Product, count() als count)") wie man das wirft ???? –

Antwort

4

Ich bin nicht sicher, wie dies mit der Abfragesyntax (wie oben) zu tun ist, aber unter Verwendung der Methodensyntax können wir einen Ausdruck < Func < wie unten gezeigt verwenden.Dieses Beispiel arbeitet gegen die Adventureworks-SQL-Server-Datenbank (Tabelle Products), und ermöglicht es Ihnen, welche Spalte zu gruppieren, um anzugeben, indem Sie eine Zeichenfolge (in diesem Beispiel habe ich gewählt, Größe)

using System; 
using System.Linq; 
using System.Linq.Expressions; 

namespace LinqResearch 
{ 
    public class Program 
    { 
     [STAThread] 
     static void Main() 
     { 
      string columnToGroupBy = "Size"; 

      // generate the dynamic Expression<Func<Product, string>> 
      ParameterExpression p = Expression.Parameter(typeof(Product), "p"); 

      var selector = Expression.Lambda<Func<Product, string>>(
       Expression.Property(p, columnToGroupBy), 
       p 
      ); 

      using (LinqDataContext dataContext = new LinqDataContext()) 
      { 
       /* using "selector" caluclated above which is automatically 
       compiled when the query runs */ 
       var results = dataContext 
        .Products 
        .GroupBy(selector) 
        .Select((group) => new { 
         Key = group.Key, 
         Count = group.Count() 
        }); 

       foreach(var result in results) 
        Console.WriteLine("{0}: {1}", result.Key, result.Count); 
      } 

      Console.ReadKey(); 
     } 
    } 
} 
1

Wenn Sie einen Blick auf C# Bits werfen, erläutert der Autor, wie Sie mit dynamischen Daten kaskadierende Filter erstellen. Es klingt nicht so, als würden Sie Dynamic Data verwenden, aber er hat einen schönen Ausdrucksersteller, der Ihnen hilfreich sein könnte. Siehe BuildQueryBody und dann der folgende Abschnitt der Erweiterungsmethoden für Iqueryable.

Da Sie keine dynamischen Daten verwenden, müssen Sie sich damit befassen, keinen Zugriff auf ein "MetaForeignKeyColumn" -Objekt zu haben, aber ich vermute, dass sein Ansatz Ihnen bei Ihrer Frage helfen könnte.

Ich hoffe, das hilft.