2009-05-11 8 views
3

En raison de certaines décisions commerciales, j'ai besoin de changer un peu ce que je faisais. Yay moi. :)LINQ - Se joint à une requête dynamique

Actuellement, j'ai:

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; 
} 

Au lieu de Foing directement, je maintenant besoin de se joindre par 2 autres tables pour appliquer le filtre correctement. J'essaie de comprendre comment joindre correctement une requête LINQ dynamique. Dans TSQL ce serait quelque chose comme:

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

J'ai également trouvé ce lien qui parle de convertir SQL en LINQ. Cela pourrait être utile: http://blogs.msdn.com/vbteam/archive/tags/Converting+SQL+to+LINQ/default.aspx. C'est pour VB.NET, mais le contenu devrait toujours être utile pour C#. –

Répondre

6

Ouch. Oui, c'est une exigence compliquée. Vous savez, les lambdas sont cumulatifs, donc vous pouvez le faire beaucoup plus simplement si vous utilisez des expressions linq successives. Notez que les expressions linq suivantes utilisent le résultat de l'expression précédente et que l'intégralité n'est pas réellement exécutée avant l'itération.

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

Je n'ai pas une bonne "réponse" pour vous, mais plus d'un côté. Découvrez LINQPad. Vous pourriez même voir une annonce sur le côté droit de cette page, aussi. Il est très pratique pour écrire des requêtes LINQ. Il pourrait être utile d'écrire et de valider cette requête LINQ et toute autre future requête LINQ que vous écrivez.

0

Essayez d'utiliser Spolty Framework. Il aide à faire une requête dynamique pour Linq To SQL et Entity Framework. Vous pouvez créer dynamiquement une jointure gauche/intérieure, ajouter des conditions, des ordres et d'autres choses. Si vous utilisez Spolty Framework, votre code ressemblera à ceci:

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>(); 
}