2010-10-29 14 views
2

J'ai une situation où je dois construire dynamiquement une requête linq basée sur les sélections de l'utilisateur. Si je devais générer dynamiquement sql je pouvais le faire de cette façon:SubSonic 3, construction dynamique ou expression au moment de l'exécution

 var sb = new StringBuilder(); 
     sb.AppendLine("SELECT * FROM products p"); 
     sb.AppendLine("WHERE p.CategoryId > 5"); 

     // these variables are not static but choosen by the user 
     var type1 = true; 
     var type2 = true; 
     var type3 = false; 

     string type1expression = null; 
     string type2expression = null; 
     string type3expression = null; 

     if (type1) 
      type1expression = "p.productType1 = true"; 

     if (type2) 
      type2expression = "p.productType2 = true"; 

     if (type3) 
      type3expression = "p.productType3 = true"; 

     string orexpression = String.Empty; 
     foreach(var expression in new List<string> 
       {type1expression, type2expression, type3expression}) 
     { 
      if (!String.IsNullOrEmpty(orexpression) && 
        !String.IsNullOrEmpty(expression)) 
       orexpression += " OR "; 

      orexpression += expression; 
     } 

     if (!String.IsNullOrEmpty(orexpression)) 
     { 
      sb.AppendLine("AND ("); 
      sb.AppendLine(orexpression); 
      sb.AppendLine(")"); 
     } 

     // result: 

     // SELECT * FROM products p 
     // WHERE p.CategoryId > 5 
     // AND (
     // p.productType1 = true OR p.productType2 = true 
     //) 

Maintenant, je dois créer une requête LINQ de la même manière.

Cela fonctionne bien avec subsonique

var result = from p in db.products 
      where p.productType1 == true || p.productType2 == true 
      select p; 

Je l'ai essayé avec PredicateBuilder http://www.albahari.com/nutshell/predicatebuilder.aspx mais qui jette une exception avec subsonique.

var query = from p in db.products 
      select p; 

var inner = PredicateBuilder.False<product>(); 
inner = inner.Or(p => p.productType1 == true); 
inner = inner.Or(p => p.productType2 == true); 

var result = query.Where(inner); 

l'exception qui est levée: NotSupportedException: The member 'productType1' is not supported à SubSonic.DataProviders.MySQL.MySqlFormatter.VisitMemberAccess.

Tout le monde a une idée comment obtenir cette requête au travail:

+0

salut SchlaWeiner, je construis aussi mes requêtes comme vous le faites. J'utilise généralement ceci pour le filtrage, le tri et la pagination. Avez-vous une manière élégante de faire ceci? –

+0

J'ai ajouté un exemple. Suivez simplement le lien fourni par Devart, téléchargez l'exemple de projet et ajoutez le fichier Dynamic.cs à votre projet. Vous devez ajouter 'using System.Linq.Dynamic' à votre code afin d'utiliser la lib. –

Répondre

1

Peut-être Dynamic LINQ sera utile?

+0

Oui, cela a fonctionné. Je suppose qu'il y a une solution plus statique, que je ne trouve pas. Mais la source linq dynamique est en effet très puissante. Merci. –

0

Voici un exemple d'utilisation, tel que demandé par geocine. Il nécessite Dynamic Linq.

 var productTypes = new int[] {1,2,3,4}; 
     var query = from p in db.products 
        select p; 

     if (productTypes.Contains(1)) 
      query.Add("productType1 = @0"); 

     if (productTypes.Contains(2)) 
      query.Add("productType2 = @0"); 

     if (productTypes.Contains(3)) 
      query.Add("productType3 = @0"); 

     if (productTypes.Contains(4)) 
      query.Add("productType4 = @0"); 

     if (productTypes.Count > 0) 
     { 
      string result = String.Join(" OR ", productTypes); 
      query = query.Where("(" + result + ")", true); 
     } 

     var result = from p in query 
        select new {Id = p.ProductId, Name = p.ProductName }; 

il semble akward mais cela fonctionne.