2009-05-11 7 views
3

Aufgrund einiger Geschäftsentscheidungen muss ich etwas von dem, was ich tat, ändern. Yay mich. :)LINQ - Joins in einer dynamischen Abfrage

Derzeit habe ich:

public IOrderedQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string,List<string>> filterDictionary) 
{ 
    string whereClause = "ProductGroupName='" + productGroupName + "' AND ProductTypeName='" + productTypeName + "'"; 
    string comma = ""; 
    foreach (KeyValuePair<string, List<string>> myKVP in filterDictionary) 
    { 
     comma = ""; 
     if (myKVP.Value.Count > 0) 
     { 
      whereClause = String.Format("{0} AND FieldName = {1} AND FieldValue IN (", whereClause, myKVP.Key); 
      foreach (string value in myKVP.Value) 
      { 
       whereClause = String.Format("{0}{1}'{2}'", whereClause, comma, value); 
       comma = ","; 
      } 
      whereClause = String.Format("{0})", whereClause); 
     } 
    } 

    var q = db.ProductDetail 
       .Where (whereClause) 
       .OrderBy ("ProductTypeName"); 
    return q; 
} 

Statt diese von FOING direkt, ich brauche jetzt durch zwei weitere Tabellen verknüpfen den Filter korrekt anzuwenden. Ich versuche herauszufinden, wie man einer dynamischen LINQ-Abfrage korrekt beitritt. In TSQL wäre es so etwas wie:

SELECT pd.* 
    FROM ProductDetail pd 
INNER JOIN ProductFilterAssignment pfa ON pd.ProductID = pfs.ProductID 
INNER JOIN ProductFilter pf ON pfs.FIlterID = pf.FIlterID 
WHERE pf.FieldName = 'var1' AND pf.FieldValue IN ('var1a','var1b','var1c',etc) 
    AND pf.FieldName = 'var2' AND pf.FieldValue IN ('var2a','var2b','var2c',etc) 
+0

Ich habe auch diesen Link gefunden, der über die Konvertierung von SQL nach LINQ spricht. Es könnte nützlich sein: http://blogs.msdn.com/vbteam/archive/tags/Converting+SQL+to+LINQ/default.aspx. Es ist für VB.NET, aber das Zeug dort sollte immer noch nützlich für C# sein. –

Antwort

6

Autsch. Ja, das ist eine komplizierte Anforderung. Weißt du, Lambdas sind kumulativ, also kannst du das viel einfacher machen, wenn du aufeinanderfolgende linq-Ausdrücke verwendest. Beachten Sie, dass nachfolgende linq-Ausdrücke das Ergebnis des vorherigen Ausdrucks verwenden und das Ganze erst dann ausgeführt wird, wenn es iteriert wird.

public IOrderedQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string,List<string>> filterDictionary) 
{ 
    // Initial select on productGroupName and productTypeName 
    var products = from product in db.ProductDetail 
        where product.ProductGroupName == productGroupName && product.ProductTypeName == productTypeName 
        select product; 

    // Now add each filter item present. 
    foreach (KeyValuePair<string, List<string>> myKVP in filterDictionary) 
    { 
     products = from product in products 
        join pfa in db.ProductFilterAssignment on product.ProductID equals pfa.ProductID 
        join pf in db.Product on pfa.FilterID equals pf.FilterId 
        where pf.FieldName == myKVP.Key && myKVP.Value.Contains(pf.FieldValue) 
        select product; 
    } 

    return products.OrderBy ("ProductTypeName"); 
} 
0

Ich habe keine gute "Antwort" für Sie, sondern eher eine Nebensache. Schauen Sie sich LINQPad an. Möglicherweise sehen Sie sogar eine Anzeige auf der rechten Seite dieser Seite. Es ist sehr glatt zum Schreiben von LINQ-Abfragen. Es könnte beim Schreiben und Validieren dieser und anderer LINQ-Abfragen, die Sie schreiben, hilfreich sein.

0

Versuchen Sie, Spolty Framework zu verwenden. Es hilft bei der dynamischen Abfrage von Linq To SQL und Entity Framework. Sie können Links/Innen-Joins dynamisch erstellen, Bedingungen, Ordnungen und andere Dinge hinzufügen. Wenn Sie Spolty Framework verwenden, wird Ihr Code wie folgt aussehen:

public IQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string, List<string>> filterDictionary) 
{ 
    // create root node 
    JoinNode productDetailNode = new JoinNode(typeof(ProductDetail)); 
    productDetailNode.AddConditions(new Condition("ProductGroupName", productGroupName), 
        new Condition("ProductTypeName", productTypeName)); 

    // if there are conditions than we create joins 
    if (filterDictionary.Count > 0) 
    { 
     // create joinNode 
     // INNER JOIN ProductFilterAssignment pfa ON pd.ProductID = pfs.ProductID 
     JoinNode productFilterAssignmentNode = new JoinNode(typeof(ProductFilterAssignment)); 
     productDetailNode.AddChildren(productFilterAssignmentNode); 

     // create joinNode 
     // INNER JOIN ProductFilter pf ON pfs.FIlterID = pf.FIlterID 
     JoinNode productFilterNode = new JoinNode(typeof(ProductFilter)); 
     productFilterNode.AddChildren(productFilterNode); 

     foreach (KeyValuePair<string, List<string>> myKVP in filterDictionary) 
     { 
      // create condition pf.FieldName = {1} And AND pf.FieldValue IN ('var1a','var1b','var1c',etc) 
      productFilterNode.AddConditions(new Condition("FieldName", myKVP.Key), 
              OrCondition.Create("FieldValue", myKVP.Value.ToArray())); 
     } 
    } 

    // create result query by JoinNode productDetailNode 
    QueryDesigner queryDesigner = new QueryDesigner(db, productDetailNode). 
             OrderBy(new Ordering("ProductTypeName")); 

    return queryDesigner.Cast<ProductDetail>(); 
}