2016-03-24 6 views
1

Zum Beispiel habe ich OData Abfrage wie diese:?OData: Sie Groß- und Kleinschreibung Vergleich mit Expression

  • /Lieferanten $ filter = Adresse/Ort eq 'Stadt'
  • /Lieferanten $ filter = enthält (Adresse/Stadt, 'Stadt')
  • /Lieferanten? $ filter = endswith (Adresse/Stadt, 'Stadt')

...

und Adresse/C Die Stadt hat nur "Stadt". Ich möchte immer noch, dass die Abfrage diesen Datensatz zurückgibt.

Ich lese this bereits, aber es scheint nur Adresse enthält Funktion. Ich könnte leicht für andere Funktionen reparieren, aber EQ ist schwieriger. Um es einfacher zu machen, habe ich darüber nachgedacht, alle String Const nur in Großbuchstaben zu ersetzen, indem Sie dies tun. ToString(). ToUpper().

Ich habe ein Problem, weil ich nicht wirklich auf den Wert zugreifen kann.

protected override Expression VisitConstant(ConstantExpression node) 
      { 
//the node.Value i get here is {value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String])} 
and of type System.Linq.Expressions.ConstantExpression. 

Wie kann ich entweder den Wert direkt in Großbuchstaben ändern oder einen Aufruf von ToString und ToUpper hinzufügen?

+0

Haben Sie das eingebaute in versucht [ 'tolower'] (http://docs.oasis-open.org/odata/odata/v4.0/errata02/ os/complete/part2-url-konventionen/odata-v4.0-errata02-os-part2-url-conventions-complete.html # _Toc406398123) Funktion? Z. B. '/ Lieferanten? $ Filter = tolower (Adresse/Stadt) eq 'Stadt'. – lencharest

+0

Ich habe keine Kontrolle darüber, welche Abfragen gesendet werden, sie werden von Benutzern erstellt. Ich bin in der Lage, Ausdruck intern zu ändern, obwohl – user21479

+0

user21479 Ich habe an dem gleichen Problem gearbeitet, und ich habe eine Idee, wie es zu lösen, aber was ich nicht weiß ist, wie man den neuen Ausdruck (Ergebnis des ExpressionVisitor) in die Abfrage-Pipeline. –

Antwort

1

Die ideale Lösung wäre, dies auf der Client-Seite mit den integrierten Filterfunktionen tolower und toupper zu handhaben. Dies würde dem Client erlauben, die Wahl zu treffen, ob mit oder ohne Berücksichtigung der Groß-/Kleinschreibung gefiltert werden soll.

Auf der Serverseite ist es derzeit die beste Vorgehensweise, den Anforderungs-URI zu ändern und ein neues Anforderungsobjekt für den geänderten URI zu generieren. Siehe OData V4 modify $filter on server side. Es gibt ein offenes Problem im Web-API-OData für eine elegantere query option interception/modification mechanism.

String-Operation direkt auf Anfrage durchführen URI wird immer fehleranfällig sein. Wir können die linked answer verbessern, indem wir das Rich Object Model für Filterausdrücke in der OData Library (ODL) nutzen. Beachten Sie, dass der Filterausdruck ODataQueryOptions.Filter.FilterClause.Expression ein abstrakter Syntaxbaum ist, der den Wert $filter darstellt.

Der Code, der benötigt Namensräumen von ODL folgt:

using Microsoft.OData.Core; 
using Microsoft.OData.Core.UriBuilder; 
using Microsoft.OData.Core.UriParser; 
using Microsoft.OData.Core.UriParser.Semantic; 
using Microsoft.OData.Core.UriParser.TreeNodeKinds; 
using Microsoft.OData.Edm; 

zunächst eine Hilfsklasse definieren die verschiedenen Knoten zum Neuschreiben, die einen Filter AST bilden. Die folgende Klasse handhabt derzeit nur BinaryOperatorNode (z. B. eq Ausdrücke).

public static class FilterExpressionHelper 
{ 
    public static SingleValueNode RewriteAsCaseInsensitive(BinaryOperatorNode node) 
    { 
     // Handle {Edm.String eq Edm.String} 
     if (node.OperatorKind == BinaryOperatorKind.Equal && node.Left.TypeReference.IsString() && node.Right.TypeReference.IsString()) 
     { 
      // Wrap both operands with toupper(). 
      node = new BinaryOperatorNode(BinaryOperatorKind.Equal, 
       new SingleValueFunctionCallNode("toupper", new List<QueryNode> { node.Left }, node.Left.TypeReference), 
       new SingleValueFunctionCallNode("toupper", new List<QueryNode> { node.Right }, node.Right.TypeReference)); 
     } 

     return node; 
    } 

    // Add methods to handle other node types; e.g., SingleValueFunctionCallNode. 
} 

Als nächstes definieren einen Helfer den rewriter aufzurufen und die Abfragezeichenfolge des Anforderungs-URI zu regenerieren (wie durch ODataQueryOptions modelliert).

public class ODataUriHelper 
{ 
    public static string RewriteQuery(ODataQueryOptions queryOptions) 
    { 
     var odataUri = BuildODataUri(queryOptions); 
     var uriBuilder = new ODataUriBuilder(ODataUrlConventions.Default, odataUri); 
     var uri = uriBuilder.BuildUri(); 
     // Do not return the leading '?'. 
     return uri.Query.Substring(1); 
    } 

    private static readonly Uri DummyServiceRoot = new Uri("http://localhost"); 
    private static readonly ODataPath DummyPath = new ODataPath(Enumerable.Empty<ODataPathSegment>()); 

    private static ODataUri BuildODataUri(ODataQueryOptions queryOptions) 
    { 
     var uri = new ODataUri(); 

     uri.ServiceRoot = DummyServiceRoot; 
     uri.Path = DummyPath; 
     uri.Filter = RewriteFilter(queryOptions.Filter?.FilterClause); 
     uri.OrderBy = queryOptions.OrderBy?.OrderByClause; 
     uri.SelectAndExpand = queryOptions.SelectExpand?.SelectExpandClause; 
     uri.Skip = queryOptions.Skip?.Value; 
     uri.Top = queryOptions.Top?.Value; 

     return uri; 
    } 

    private static FilterClause RewriteFilter(FilterClause filterClause) 
    { 
     if (filterClause != null) 
     { 
      var filterExpr = filterClause.Expression; 
      var binaryExpr = filterExpr as BinaryOperatorNode; 

      if (binaryExpr != null) 
      { 
       filterExpr = FilterExpressionHelper.RewriteAsCaseInsensitive(binaryExpr); 
       filterClause = new FilterClause(filterExpr, filterClause.RangeVariable); 
      } 

      // Add support for other node types here. 
     } 

     return filterClause; 
    } 
} 

Schließlich binden sie alle zusammen mit einer benutzerdefinierten Version des EnableQuery Attribut, das Umschreiben bedingt ausführt.

public class CustomEnableQueryAttribute : EnableQueryAttribute 
{ 
    public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions) 
    { 
     if (queryOptions.Filter != null) 
     { 
      var query = ODataUriHelper.RewriteQuery(queryOptions); 
      var uri = new UriBuilder(queryOptions.Request.RequestUri) { Query = query }; 
      var request = new HttpRequestMessage(HttpMethod.Get, uri.Uri); 

      queryOptions = new ODataQueryOptions(queryOptions.Context, request); 
     } 

     return base.ApplyQuery(queryable, queryOptions); 
    } 
} 
0

einfach:

?$filter=contains(tolower(siteName),tolower(%27michel%27)) 
          ---^---   ---^--- 
          Field   value to find 

?$filter=contains(tolower(siteName),tolower(%27Michel%27)) 
?$filter=contains(tolower(siteName),tolower(%27MiCHel%27))