2010-10-05 2 views
7

ho voluto usare un metodo che ho creato all'interno di un coz interrogazione ho bisogno di implementare un particolare tipo di filtro ...Come creare un metodo che supporta la traduzione in sql?

return manager.Clients.SelectAll().Where(cli => cli.Name.SatisfyFilter(filter.Name) && cli.LastName.SatisfyFilter(filter.LastName) && cli.MiddleName.SatisfyFilter(filter.MiddleName)).ToList(); 

ma ho l':

"Metodo 'booleano SatisfyFilter (Sistema. String, System.String) 'non ha traduzione supportata in SQL. "

errore

Il mio metodo è:

public static bool SatisfyFilter(this string palavra, string filtro) 

stessa cosa del

public bool Contains(string value) 

nel tipo stringa, e contiene funziona bene ...

ho bisogno questo metodo per eseguire su IQueryable, coz my table ha 25 milioni di client ...

ho visto sul profiler di sql che la contiene è trasformato in SQL ...

Come faccio a implementare il mio metodo per inviare il codice del filtro correlativa a SQL? =/

+2

Perché non usare solo contiene? – Paddy

risposta

4

Una risposta semplice è non è possibile. Il traduttore LINQ to SQL riconosce solo alcuni dei metodi standard di .NET e non è possibile aggiungerne altri.

  • Se avete bisogno di una cosa del genere, è necessario creare albero di espressione in modo esplicito (da utilizzare come il corpo della espressione lambda). Un modo diretto per farlo è usare i metodi della classe Expression, ma può essere molto semplificata.

  • Forse l'opzione migliore è utilizzare lo LINQKit project. Permette di chiamare altre espressioni lambda (metodo non proprio, ma chiuso). Esso fornisce un metodo AsExpandable estensione che permette di scrivere:

    Expression<Func<Purchase, bool>> customFunction = ... 
    var data = new MyDataContext(); 
    var query = 
        from c in data.Purchases.AsExpandable() 
        where customFunction.Compile()(c) 
        select c.Name; 
    

    Il customFunction è una funzione lambda compilato come un albero di espressione ed è possibile utilizzarlo all'interno di una query. L'estensione AsExpandable sostituisce l'uso con il corpo della funzione, quindi LINK to SQL translator può gestirlo. Puoi leggere ulteriori informazioni su come funziona in my blog post.

  • Altra alternativa che è più in dettaglio discussa da altri è quella di implementare la funzionalità come una funzione definita dall'utente SQL. Quindi è possibile trascinare la funzione nel contesto dati e chiamare la funzione dalla query. Il traduttore inserirà semplicemente una chiamata alla funzione SQL.

1

Se è possibile eseguire il mapping di questo in un udf, è possibile trascinare il file udf nel data-contex. Quando si accede tramite il contesto dati LINQ-to-SQL può eseguire la traduzione.

Se si limita a filtrare un iqueryable, è possibile scrivere un metodo che utilizza solo Dove (restituendo un nuovo iqueryable) che può funzionare correttamente.

Se hai bisogno di una tazza in più, potresti dover sporcare manualmente gli alberi di espressione.

0

Il modo più semplice per farlo è capire come convertire la funzione 'SatisfyFilter' in una serie di comandi linq con una traduzione accettata. Temo che non ci sia davvero un altro modo "facile" per usare la tua funzione personalizzata senza filtrare i tuoi 25 milioni di clienti fino a un numero più materializzabile.

6

Creare una funzione utente sul server SQL che corrisponda al codice C#. Diciamo che è stato chiamato "dbo.SatsFilter".

Creare un metodo sul vostro sostituzione DataContext, dicono che assomiglia a:

public bool SatisfiesFilter(string name, string filter) 
{ 
    // some sort of implementation. 
} 

decorare il metodo di C# con [Function] e [Parameter] attributi in modo che appaia qualcosa di simile:

[Function(Name="dbo.SatsFilter",IsComposable=true)] 
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter) 

IsComposable=true significa che la sua una funzione piuttosto che una stored procedure e può quindi essere utilizzata come parte di una query più ampia.

È ora possibile utilizzare questo metodo di DataContext e verrà convertito in SQL quando appropriato oppure il C# verrà utilizzato nelle query eseguite in memoria.

Si noti inoltre, che se si voleva utilizzare solo SQL per tutto il tempo (a volte utile) si potrebbe chiamare in SQL quando il metodo viene chiamato in codice C#:

[Function(Name="dbo.SatsFilter",IsComposable=true)] 
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter) 
{ 
    return (bool)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), name, filter).ReturnValue; 
} 

Questo non è molto utile quando l'equivalente di C# è conveniente, poiché significa un colpo al database e qualche traduzione, ma è utile se la funzione utente dipende dallo stato del database o è difficile da tradurre bene in C#

+0

Vuoi dire che dovrò ereditare la classe DataContext e quindi inserire il metodo SatisfiesFilter come metodo di istanza al suo interno? e poi mentre spari LINQ alle query SQL dovrei usare la mia nuova classe ereditata. – RBT

+0

@RBT Penso di sì. È passato un po 'di tempo. –

+0

Potete per favore dare un'occhiata al mio problema al seguente link. Sto provando la stessa cosa ma ottenendo un errore. http://stackoverflow.com/questions/37814449/linq-to-sql-unable-to-use-sql-server-udfs-in-linq-query – RBT