2009-08-04 15 views
6

Sto cercando di fare un confronto come base di un parametro esterno (passato da un modulo di ricerca) che determina il tipo di confronto ("%string" o "string%" o "%string%")Linq, espressioni, NHibernate e come confronto

stavo pensando nella seguente direzione:

query = query.Where(
    Entity.StringProperty.Like("SearchString", SelectedComparsionType) 
) 

Come metodo sarebbe più in base al tipo selezionato ritorno .StartsWith() o .EndsWith() o .SubString()

La mia conoscenza delle espressioni è apparentemente lontana dal grande, dal momento che non sono stato in grado di costruire un metodo che potesse fornire il risultato corretto (confronto lato server in SQL come con il metodo StartsWith).

risposta

17

Il modo più semplice

Basta usare

if (comparison == ComparisonType.StartsWith) 
    query = query.Where(e => e.StringProperty.StartsWith("SearchString")); 
else if ... 

Il modo più duro

Se si vuole fare qualcosa di simile, o assicurarsi che il vostro fornitore di LINQ può essere detto di questo nuovo metodo in qualche modo, e come si traduce in SQL (improbabile), o impedisce al metodo di raggiungere il provider LINQ e fornire al provider qualcosa che capisce (ha rd). Ad esempio, invece di

query.Where(e => CompMethod(e.StringProperty, "SearchString", comparsionType)) 

è possibile creare qualcosa di simile

var query = source.WhereLike(e => e.StringProperty, "SearchString", comparsionType) 

con il seguente codice

public enum ComparisonType { StartsWith, EndsWith, Contains } 

public static class QueryableExtensions 
{ 
    public static IQueryable<T> WhereLike<T>(
     this IQueryable<T> source, 
     Expression<Func<T, string>> field, 
     string value, 
     SelectedComparisonType comparisonType) 
    { 
     ParameterExpression p = field.Parameters[0]; 
     return source.Where(
      Expression.Lambda<Func<T, bool>>(
       Expression.Call(
        field.Body, 
        comparisonType.ToString(), 
        null, 
        Expression.Constant(value)), 
      p)); 
    } 
} 

È anche possibile aggiungere ulteriori criteri in questo modo

var query = from e in source.WhereLike(
       e => e.StringProperty, "SearchString", comparsionType) 
      where e.OtherProperty == 123 
      orderby e.StringProperty 
      select e; 

Il modo molto, molto difficile

Sarebbe (tecnicamente) essere possibile riscrivere l'albero di espressione prima che il provider lo vede, in modo da possibile utilizzare la query che aveva in mente, in primo luogo, ma si' d dover

  • creare un Where(this IQueryable<EntityType> source, Expression<Func<EntityType, bool>> predicate) per intercettare il Queryable.Where,
  • riscrivere l'albero di espressione, sostituendo il tuo CompMethod, ovunque essa sia, con uno dei metodi String,
  • chiama l'originale Queryable.Where con l'espressione riscritta,
  • e in primo luogo, è possibile seguire il metodo di estensione sopra in primo luogo!

Ma probabilmente è troppo complicato per quello che avevi in ​​mente.

+0

Ruben: Fenomenale, questa è un'inferno di una spiegazione: completa, comprensibile, completa ed esattamente ciò che stavo cercando, grazie. Vorrei anche ringraziare gli altri per la loro assistenza. –

-1

Per risolvere questo problema è preferibile utilizzare Regex.

+0

Questo non comporterebbe un operatore LIKE del database, che penso che l'OP desideri – MattH

1

Suona come si dovrebbe essere che vogliono utilizzare:

query = query.Where(
Entity.StringProperty.Contains("SearchString") 
) 

Questo dovrebbe mappare:

WHERE StringProperty LIKE '%SearchString%' 

Questo dovrebbe funzionare anche per le maschere di ricerca più avanzate, come "Mr Sm% th?" ma non ho ancora provato nessuna stringa di ricerca del genere.


UPDATE: Sulla base di PO Modifica

Suona come quello che si sta chiedendo è qualcosa di simile al seguente:

public enum SelectedComparsionType 
    { 
     StartsWith, 
     EndsWith, 
     Contains 
    } 

public static bool Like(this string searchString, string searchPattern, SelectedComparsionType searchType) 
{ 
    switch (searchType) 
    { 
     case SelectedComparsionType.StartsWith: 
      return searchString.StartsWith(searchPattern); 
     case SelectedComparsionType.EndsWith: 
      return searchString.EndsWith(searchPattern); 
     case SelectedComparsionType.Contains: 
     default: 
      return searchString.Contains(searchPattern); 
    } 
} 

Questo permetterebbe di scrivere codice come richiedete , ovvero:

query = query.Where(
Entity.StringProperty.Like("SearchString", SelectedComparsionType.StartsWith) 
) 

Tuttavia, personalmente, sostituirei qualsiasi utilizzo di SelectedComparsionType, con una chiamata diretta alla funzione di stringa richiesta. I.e

query = query.Where(
Entity.StringProperty.StartsWith("SearchString") 
) 

Poiché questo verrà comunque associato a una query "LIKE" SQL.

0

Questo è esattamente quello che avevo in mente, grazie. Avevo già qualcosa di simile, ma non è stato tradotto in SQL. Per esempio, ha funzionato se ho fatto questo direttamente:

Entity.StringProperty.EndsWith("SearchString"); 

Non ha funzionato se ho usato un metodo dedicato:

CompMethod("BaseString","SearchString",SelectedComparsionType.EndsWith) 

penso che probabilmente ha qualcosa a che fare con la valutazione di espressione, i Non sono sicuro di cosa.