2012-04-12 8 views
8

Ho una tabella di database Item e l'accesso con linq-to-sql.Espressione non statica <Func<X>> con accesso a 'questo'

posso definire un custom metodo IsSpecial() articoli che restituisce vero se la radice quadrata di Item.id è ancora:

partial class Item 
{ 
    public static Expression<Func<Item, bool>> IsSpecial = (i => Math.Sqrt(i.Id)%2==0); 
} 

allora posso usare tale proprietà in una query LINQ to SQL in questo modo:

datacontext.Item.Where(Item.IsSpecial) 

Ora, per motivi estetici, voglio fare IsSpecial non statico e modificarlo in modo da poter chiamare in questo modo:

datacontext.Item.Where(i => i.IsSpecial()) 

Idealmente questo permetterebbe anche combinando di istruzioni, quale il sopra (di lavoro) snytax non consente:

datacontext.Item.Where(i => i.IsSpecial() && i.Id >100) 

Qual è la sintassi corretta per definire questo metodo?

Questo non funziona:

partial class Item 
{ 
    public Expression<Func<bool>> IsSpecial = (() => Math.Sqrt(this.Id)%2==0); 
    // 'this' keyword not available in current context 
} 

edit: Sto cominciando a sospettare che io chiedo per qualcosa che la sintassi semplicemente non permette

Credo di poter live con datacontext.Item.Where(Item.IsSpecial).Where(i => i>100)

+0

BTW 'datacontext.Item. Dove (i => Item.IsSpecial (i)) 'non verrà compilato. – leppie

+0

Perché si sta definendo una proprietà IsSpecial di tipo Func invece di definire un metodo IsSpecial? O anche solo una proprietà IsSpecial di tipo bool? –

+0

'datacontext.Item.Where (Item.IsSpecial)' compila comunque. – leppie

risposta

4
partial class Item 
{ 
    public static Expression<Func<Item, bool>> IsSpecial = (i => Math.Sqrt(i.Id)%2==0); 
} 

Suggerimento: aggiungere la parola chiave readonly.

allora posso usare tale proprietà in una query LINQ to SQL come questo:

datacontext.Item.Where(Item.IsSpecial) 

Già, perché Where accetta un parametro di tipo Expression<Func<Item, bool>>, che Item.IsSpecial è.

Ora, per motivi estetici, voglio fare IsSpecial non statico e modificarlo in modo da poter chiamare in questo modo:

datacontext.Item.Where(i => i.IsSpecial()) 

La ragione per cui questo non funziona è perché non è IsSpecial una funzione, è un albero di espressione. () può essere applicato solo alle funzioni. Un albero di espressioni descrive una funzione, ma non è una. È possibile creare una vera e propria funzione utilizzando expression.Compile():

datacontext.Item.Where(i => (IsSpecial.Compile()) (i)) 

Tuttavia, questo non funzionerà, perché ancora una volta, Where viene passato un albero di espressione, e IsSpecial.Compile() non è effettivamente chiamato. LINQ to SQL tenta di convertirlo in SQL, non riesce perché non riconosce Expression.Compile e genera un'eccezione.

Tuttavia, se si potesse sostituire (IsSpecial.Compile()) prima di LINQ to SQL dovesse vederlo ...

Ecco dove LINQKit è disponibile in:

Esso fornisce solo un po 'di manipolazione albero di espressione per farlo funzionare.

datacontext.Item.AsExpandable().Where(i => (IsSpecial.Compile()) (i)) 

Il .AsExpandable() crea un wrapper datacontext.Item di pre-filtro l'espressione.

Idealmente questo sarebbe anche permettere la combinazione di dichiarazioni, che il sopra (di lavoro) snytax non consente:

datacontext.Item.Where(i => i.IsSpecial() && i.Id >100) 

Nessun problema:

datacontext.Item.AsExpandable().Where(i => (IsSpecial.Compile()) (i) && i.Id > 100) 
+0

questo sembra molto promettente, lo verificherà, Grazie! Sono un po 'scettico riguardo l'inclusione di un'altra libreria solo per questo, ma il link a linqkit mi ha portato anche a http://tomasp.net/blog/linq-expand.aspx che sembra discutere questo problema in maggior dettaglio – HugoRune

2

È possibile utilizzare direttamente IsSpecial:

partial class Item 
{ 
    public static Expression<Func<Item, bool>> IsSpecial = (i => Math.Sqrt(i.Id)%2==0); 
} 

datacontext.Item.Where(Item.IsSpecial) 
+0

+1 Prima soluzione che di fatto verrà compilata. Comunque ho fatto un commento sulla stessa cosa al momento :) – leppie

+0

Scusa, ho incasinato quando ho copiato la sintassi nella mia domanda iniziale, questo è quello che intendevo scrivere. Idealmente, vorrei cambiarlo in qualcosa di simile a '(NOT VALID :) datacontext.Item.Where (i => i.isSpecial() && i.Id> 100 && [more properties]', tuttavia sto iniziando a sospettare che ciò che sto chiedendo è impossibile – HugoRune

1

Prova a mettere il compito di IsSpecial in un costruttore e hanno tutti il ​​delegato altri costruttori ad esso, oppure si potrebbe utilizzare un metodo parziale come OnCreated assegnare l'espressione IsSpecial. All'interno di partial class Item

partial void OnCreated() 
{ 
    IsSpecial =() => Math.Sqrt(this.Id)%2==0; 
} 

In questo modo sarà sempre assegna IsSpecial, e consentire l'accesso a "questo".

+0

questo funziona nella misura in cui posso usare "questo" in un'espressione in questo modo.Tuttavia Linq insisterà sul passaggio di un parametro nell'espressione utilizzata all'interno di una clausola .Where, così() => xyz non dovrebbe funzionare , deve essere (item) => xyz, il che significa che devo ignorare un parametro passato, e il tutto diventa disordinato.Tuttavia questo suggerimento mi ha aiutato un bel po 'a risolvere un problema correlato, quindi grazie! – HugoRune

+0

@HugoRune Looking ad alcuni dei tuoi commenti precedenti, io * penso * (non ne ho davvero idea) che questo funzionerebbe come da uno dei commenti come hai dichiarato che volevi: 'datacontext.Item.Where (i => i.IsSpecial() && io.Id> 100 && [altre proprietà] ' – JKor

+0

sì, lo pensavo anch'io, ma si scopre che questo non è possibile in questo modo. Lasciando da parte il problema "questo", questo non funzionerà anche se uso una costante anziché "questo". Motivo: IsSpecial è un albero espressione, non una funzione semplice o lambda. Chiamare 'IsSpecial()' non è una sintassi valida. 'I => i.IsSpecial && i.Id> 100' non è una sintassi valida, non è possibile concatenare alberi di espressioni come questo. La cosa confusa è che se io uso un semplice delegato o funzione invece di un'espressione >, esso compilerà e lavorerà con il normale Linq, ma linq-to-sql è una bestia diversa – HugoRune

Problemi correlati