Domanda

C'è un modo per utilizzare il metodo CompiledQuery.Compile per compilare l'espressione associata ad un IQueryable? Attualmente ho un IQueryable con un grande albero di espressione dietro di esso. L'IQueryable è stato costruito utilizzando diversi metodi che ciascuno dei componenti di alimentazione. Ad esempio, due metodi possono restituire IQueryables che vengono poi uniti in un terzo. Per questo motivo non posso definire in modo esplicito l'intera espressione all'interno della chiamata al metodo di compilazione ().

Speravo di passare l'espressione al metodo di compilazione come someIQueryable.Expression, tuttavia questa espressione non è nella forma richiesta dal metodo di compilazione. Se provo e andare in giro questo mettendo la query direttamente nel metodo di compilazione, ad esempio:

    var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(dc => dc.getUsers());
    var bar = foo(this);

dove faccio la forma chiamata entro un DataContext, ottengo un errore che dice che "getusers non è mappato come una stored procedure o una funzione definita dall'utente". Anche in questo caso non posso semplicemente copiare il contenuto del metodo getusers al punto in cui faccio la chiamata di compilazione in quanto a sua volta fa uso di altri metodi.

C'è qualche modo per passare l'Expression sulla IQueryable tornato da "getusers" nel metodo Compile?

Aggiornamento Ho cercato di forzare la mia volontà sul sistema con il seguente codice:

    var phony = Expression.Lambda<Func<DataContext, IQueryable<User>>>(
        getUsers().Expression, Expression.Parameter(typeof(DataContext), "dc"));

    Func<DataContext, IQueryable<User>> wishful = CompiledQuery.Compile<DataContext, IQueryable<User>>(phony);
    var foo = wishful(this);

foo finisce per essere:

{System.Data.Linq.SqlClient.SqlProvider + OneTimeEnumerable`1 [Model.Entities.User]}

Non ho la possibilità di vedere i risultati in foo, come invece di offrire per espandere i risultati ed eseguire la query vedo solo il messaggio "Operazione potrebbe destabilizzare il runtime".

Ho solo bisogno di trovare un modo per la stringa SQL per essere generato solo una volta e utilizzato come comando parametrizzato durante le richieste successive, posso fare questo manualmente utilizzando il metodo GetCommand sul contesto dei dati, ma poi devo impostare in modo esplicito tutti i parametri e fare l'oggetto stesso mappatura, che dista poche centinaia di righe di codice data la complessità di questo particolare query.

Aggiornamento

John Rusk ha fornito le informazioni più utili, quindi gli ha assegnato la vittoria su questo. Tuttavia, qualche ritocco in più è stato richiesto e c'erano un paio di altri problemi che ho incontrato lungo la strada così ho pensato 'Espandi' sulla risposta. In primo luogo, l' 'operazione potrebbe destabalize il runtime' errore non era dovuto alla compilazione dell'espressione, era in realtà a causa di qualche colata in profondità nella struttura di espressione. In alcuni luoghi avevo bisogno di chiamare il metodo .Cast<T>() per lanciare formalmente oggetti, anche quando erano del tipo corretto. Senza entrare nei dettagli questo era fondamentalmente richiesto quando diversi espressione sono stati combinati in un unico albero e ogni ramo potrebbe restituire un tipo diverso, che erano ciascun tipo secondario di una classe comune.

Dopo aver risolto il problema destabalizing, sono tornato al problema di compilazione. soluzione ampliare John era quasi. Sembrava per le espressioni chiamata di metodo nella struttura e ha cercato di risolverli per l'espressione di fondo che il metodo di solito tornare. I miei riferimenti a espressioni non sono stati forniti da chiamate di metodo, ma invece proprietà. Quindi avevo bisogno di modificare l'espressione visitatore che effettua l'espansione per includere questi tipi:

protected override Expression VisitMemberAccess(MemberExpression m) {
    if(m.Method.DeclaringType == typeof(ExpressionExtensions)) {
        return new ExpressionExpander().Visit((Expression)(((System.Reflection.PropertyInfo)m.Member).GetValue(null, null)));
    }
    return base.VisitMemberAccess(m);
}

Questo metodo potrebbe non essere adatto in tutti i casi, ma dovrebbe aiutare chi si trova nella stessa situazione.

È stato utile?

Soluzione

Una cosa come questa funziona, almeno nel mio test:

Expression<Func<DataContext, IQueryable<User>> queryableExpression = GetUsers();
var expressionWithSomeAddedStuff = (DataContext dc) => from u in queryableExpression.Invoke(dc) where ....;
var expressionThatCanBeCompiled = expressionWithSomeAddedStuff.Expand();
var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(expressionThatCanBeCompiled);

Questo sembra un po 'prolisso, e ci sono probabilmente i miglioramenti che si possono fare.

Si punto chiave è che usa l'Invoke ed espandere i metodi da LinqKit. In sostanza permettono di costruire una query, attraverso la composizione, e quindi compilare il risultato finale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top