Les clauses de type dynamic-où-de Linq-To-Sql sont-elles même possibles dans Framework 3.5?

MISE À JOUR: il fonctionne maintenant
J’ai pu enfin le terminer. Un exemple de travail est détaillé dans une réponse ci-dessous (que je pourrai marquer dans 2 jours).


Tout en bas ici faisait partie de la question initiale

Au cours des 3 derniers jours, j’ai essayé de créer une clause dynamic-where-sur un DataContext DBML en utilisant des exemples de code issus de questions postées ici et d’ autres sources également … aucun n’a fonctionné !

Pour les raisons ci-dessous, je commence à me demander si cela est même POSSIBLE d’utiliser le Framework 3.5:

  1. Predicate Builder note Framework 4.0 sur leur site.
  2. Certaines réponses ici parlent d’une version équivalente d’ Invoke dans la version 4.0 (j’ai donc de l’espoir ici).
  3. …Je pourrais continuer, mais vous voyez l’idée.

Je suis vraiment désemparé et je semble être “accrocheur” … et j’ai besoin de conseils judicieux sur la façon de procéder.

La version originale a eu un certain succès, mais seulement quand:
La SEULE fois que j’ai eu un “soupçon” de succès, les données sont arrivées (toutes les 6178 lignes) mais aucune WHERE CLAUSE n’a été appliquée. Cela a été démontré par l’ absence de toute WHERE CLAUSE appliquée dans le dataContext.GetCommand(query).CommandText SQL trouvé dans le dataContext.GetCommand(query).CommandText .

L’autre version n ° 1 échoue:
Et génère cette erreur: “La méthode ‘System.Object DynamicInvoke (System.Object [])’ n’a aucune traduction prise en charge en SQL.”

 // VERSION 1: public static class PredicateBuilder { public static Expression<Func> True() { return f => true; } public static Expression<Func> False() { return f => false; } public static Expression<Func> Or(this Expression<Func> expr1, Expression<Func> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda<Func>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); } public static Expression<Func> And(this Expression<Func> expr1, Expression<Func> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda<Func>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); } public static Expression<Func> SsortingngLike(Expression<Func> selector, ssortingng pattern) { var predicate = PredicateBuilder.True(); var parts = pattern.Split('%'); if (parts.Length == 1) // not '%' sign { predicate = predicate.And(s => selector.Comstack()(s) == pattern); } else { for (int i = 0; i  0) { if (i == 0) { predicate = predicate.And(s => selector.Comstack()(s).StartsWith(p)); } else if (i == parts.Length - 1) { predicate = predicate.And(s => selector.Comstack()(s).EndsWith(p)); } else { predicate = predicate.And(s => selector.Comstack()(s).Contains(p)); } } } } return predicate; } } // VERSION 1: public List QueryDocuments(ssortingng searchText, ssortingng customerSiteId, List filterIds) { var where = PredicateBuilder.True(); var searches = new List(searchText.Split(' ')); searches.ForEach(productName => { ssortingng like = productName.Replace('"', '%') .Replace('*', '%'); where = PredicateBuilder.SsortingngLike(x => x.DocumentName, like); }); var results = DocumentCollectionService.ListQuickFind(where, null); // Do other stuff here... return results; } // VERSION 1: public static List ListQuickFind(Expression<Func> where, Expression<Func> orderBy) { var connectionSsortingng = GetConnectionSsortingng(ES_DOCUMENTS_CONNECTION_NAME); List results = null; using (HostingEnvironment.Impersonate()) { using (var dataContext = new ES_DocumentsDataContext(connectionSsortingng)) { IQueryable query = dataContext.vw_QuickFindResults; query = query.Where(where); results = query.ToList(); } } return results; } 

L’autre version n ° 2 échoue:
Et génère cette erreur: “La méthode ‘Boolean Like (System.Ssortingng, System.Ssortingng)’ ne peut pas être utilisée sur le client, c’est uniquement pour la traduction en SQL.”

 // VERSION 2: public List QueryDocuments(ssortingng searchText, ssortingng customerSiteId, List filterIds) { Func where = null; Func<string, Func> buildKeywordPredicate = like => x => SqlMethods.Like(x.DocumentName, like); Func<Func, Func, Func> buildOrPredicate = (pred1, pred2) => x => pred1(x) || pred2(x); // Build LIKE Clause for the WHERE var searches = new List(searchText.Split(' ')); searches.ForEach(productName => { ssortingng like = productName.Replace('"', '%') .Replace('*', '%'); where = (where == null) ? buildKeywordPredicate(like) : buildOrPredicate(where, buildKeywordPredicate(like)); }); var results = DocumentCollectionService.ListQuickFind(where, null); // Do other stuff here... return results; } // VERSION 2: public static List ListQuickFind(Expression<Func> where, Expression<Func> orderBy) { var connectionSsortingng = GetConnectionSsortingng(ES_DOCUMENTS_CONNECTION_NAME); List results = null; using (HostingEnvironment.Impersonate()) { using (var dataContext = new ES_DocumentsDataContext(connectionSsortingng)) { var query = dataContext.vw_QuickFindResults.AsEnumerable(); query = query.Where(where); results = query.ToList(); } } return results; } 

Avez-vous essayé de créer la requête vous-même en utilisant uniquement les classes Exression? Il ne devrait y avoir aucun problème particulier là-bas. Il est en fait relativement facile à apprendre. Vous pouvez écrire un exemple de requête, puis voir comment il est composé dans le débogage:

 Expression> exp = (s) => s.Contains("your query"); 

Ensuite, il suffit de regarder la variable exp dans la montre et vous pouvez voir la structure. Cet exemple particulier devrait être composé comme ceci:

 Expression constant = Expression.Constant("your query"); Expression p = Expression.Param(typeof(ssortingng); Expression contains = Expression.Call(p, "Contains", constant); Expression> lambda = Expression.Lamba(contains, p); // Now you can send this to your ORM 

Pour ce que je peux vous dire, j’avais utilisé LinqKit et PredicateBuilder au début de l’année 2010 avec .Net 3.5, EF 1.0 et EF Poco Adaptor. A l’époque, LinqKit était compilé pour Net 3.5.

Peut-être que si vous demandez à l’auteur (Albahari), il pourrait vous envoyer (ou poster sur le site) la version 3.5 de cela. Je ne l’ai plus parce que c’est dans des projets de mon ancien lieu de travail et je n’y ai pas access.

En passant, je sens que votre douleur est forcée de travailler avec 3,5 après presque 2 ans de présence de .Net 4.

C’EST LA BONNE RÉPONSE
Voici la version de travail pour ceux qui en ont besoin. Le problème était une COMBINAISON de choses. La première de ces lignes était la suivante:

var where = PredicateBuilder.True();

Cela devrait être False

var where = PredicateBuilder.False();

Je ne sais pas pourquoi … mais d’autres changements s’imposaient également.

 public static class PredicateBuilder { public static Expression> True() { return f => true; } public static Expression> False() { return f => false; } public static Expression> Or(this Expression> expr1, Expression> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); } public static Expression> And(this Expression> expr1, Expression> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); } } public List QueryDocuments(ssortingng searchText, ssortingng customerSiteId, List filterIds) { var wildCards = new ssortingng[] { "*", "\"" }; var where = PredicateBuilder.False(); var searches = new List(searchText.Split(' ')); // TODO: <-- If more complex searches are needed we'll have to use RegularExpressions // SEARCH TEXT - WHERE Clause searches.ForEach(productName => { Boolean hasWildCards = (productName.IndexOfAny(new char[] { '"', '*' }) != -1); if (hasWildCards) { Int32 length = productName.Length; if (length > 1) { ssortingng like = productName.Replace("%", "") .Replace("*", ""); ssortingng first = productName.Subssortingng(0, 1); ssortingng last = productName.Subssortingng(length - 1); // Contains if (wildCards.Contains(first) && wildCards.Contains(last)) where = where.Or(p => p.DocumentName.Contains(like) || p.DocumentTitle.Contains(like)); // EndsWith else if (wildCards.Contains(first)) where = where.Or(p => p.DocumentName.EndsWith(like) || p.DocumentTitle.EndsWith(like)); // StartsWith else if (wildCards.Contains(last)) where = where.Or(p => p.DocumentName.StartsWith(like) || p.DocumentTitle.StartsWith(like)); // Contains (default) else where = where.Or(p => p.DocumentName.Contains(like) || p.DocumentTitle.Contains(like)); } else // Can only perform a "contains" where = where.Or(p => p.DocumentName.Contains(productName) || p.DocumentTitle.Contains(productName)); } else // Can only perform a "contains" where = where.Or(p => p.DocumentName.Contains(productName) || p.DocumentTitle.Contains(productName)); }); // FILTER IDS - WHERE Clause var filters = GetAllFilters().Where(x => filterIds.Contains(x.Id)).ToList(); filters.ForEach(filter => { if (!filter.IsSection) where = where.And(x => x.FilterName == filter.Name); }); var dataSource = DocumentCollectionService.ListQuickFind(where); var collection = new List(); // Other UNRELATED stuff happens here... return collection; } public static List ListQuickFind(Expression> where) { var connectionSsortingng = GetConnectionSsortingng(ES_DOCUMENTS_CONNECTION_NAME); List results = null; using (HostingEnvironment.Impersonate()) { using (var dataContext = new ES_DocumentsDataContext(connectionSsortingng)) { var query = dataContext.vw_QuickFindResults.Where(where).OrderBy(x => x.DocumentName).OrderBy(x => x.DocumentTitle); results = query.ToList(); } } return results; }