2010-11-03 12 views
7

Ho un metodo chiamato GetAge (DateTime birthDay). Voglio utilizzare questo metodo nella query di Linq passando il compleanno e in base al valore dell'età restituito è necessario per alcuni logica.Metodo call class all'interno di Linq Query

voglio qui di seguito query in formato LINQ -

from customer in contetx.Customer where 
    if GetAge(customer.BirthDate) > 20 and customer.accountType="Savings" 
    or 
    if(GetAge(customer.BirthDate) > 40 and customer.AccountType="Current" 

aiuto immediato sarebbe molto apprezzato.

+2

È questo LINQ to SQL? – Ani

+0

Questo è Linq alle entità. Sto usando Entity Framework. –

risposta

6
context.Customer 
     .AsEnumerable() // because the method has no translation to SQL 
     .Where(customer => (GetAge(customer.BirthDate) > 20 && customer.AccountType == "Savings") 
         || (GetAge(customer.BirthDate) > 40 && customer.AccountType == "Current")); 

Il .AsEnumerable è necessario se si sta tentando di interrogare un database SQL come metodo GetAge nel codice non avrà traduzione in SQL. In tal caso, la chiamata a .AsEnumerable recupera i risultati della query fino a quel punto e quindi si lavora con gli oggetti locali su cui il metodo può operare.

Se non si desidera recuperare tutti i risultati a quel punto perché il numero di record è elevato, è sempre possibile replicare la logica dal metodo che si desidera chiamare nella query (Sto indovinando la logica qui):

Poiché le operazioni sono tutte disponibili in SQL, funzionerà.

Se il metodo che si sta tentando di chiamare è particolarmente complesso, è sempre possibile spostarlo su un metodo di estensione che prende uno IQueryable e restituisce un IQueryable. Il contenuto del metodo dovrà comunque avere una traduzione valida in SQL ma aiuterà a nascondere una logica più complicata.

Ad esempio, la query di cui sopra potrebbe essere fatto per assomigliare a questo:

context.Customers.WhoAreValidByAge(); 

Dove WhoAreValidByAge è definito come:

public static IQueryable<Customer> WhoAreValidByAge(this IQueryable<Customer> customers) 
{ 
    cusomters.Select(c => new { Customer = c, Age = (DateTime.Today.Year - c.BirthDate.Year) } 
      .Where(c => (c.Age > 20 && c.Customer.AccountType == "Savings") 
         || (c.Age > 40 && c.Customer.AccountType == "Current")) 
      .Select(c => c.Customer) 
} 

Se la logica contenuta nel metodo non si traduce a SQL per qualche motivo sebbene non abbia altra scelta che convertire i risultati impostati in LinqToObjects. In tal caso, suggerirei di filtrare i risultati il ​​più possibile in SQL prima di chiamare AsEnumerable.

+2

Non penso sia necessario chiamare 'AsEnumerable()'. –

+0

Sta operando direttamente sul contesto usando un metodo che, per quanto ne so data l'informazione nella domanda, non ha una traduzione diretta a Sql. Se non esegue la conversione in LinqToObjects (utilizzando .AsEnumable() o .ToList()), il tentativo di accedere alle informazioni restituite dalla query genererà NotSupportedException con il messaggio Metodo 'GetAge' non ha traduzione supportata in SQL ... –

+0

right Calling AsEnumerable può recuperare inutilmente tutti i dati in quel punto del tempo nella query dal database. –

11
var customers = from customer in contetx.Customer 
       let age = GetAge(customer.BirthDate) 
       where (age > 20 && customer.accountType == "Savings") || 
         (age > 40 && customer.accountType == "Current") 
       select customer; 
+0

+1 | Bello, non conoscevo la parola chiave let? –

+0

Sì, evita di ricalcolare l'età due volte. –

+0

heyy questo è fantastico ... non so 'let' parola chiave .. Darin ur champ ... Grazie mille mi sono risparmiato molto del mio tempo ... –

0

Si potrebbe fare questo:

var query = from customer in contetx.Customer 
    where (GetAge(customer.BirthDate) > 20 && customer.AccountType == "Saving") || 
      (GetAge(customer.BirthDate) > 40 && customer.AccountType == "Current") 
    select customer; 

Si poteva andare in giro chiamando GetAge due volte utilizzando la parola chiave let come ha fatto Darin.

var query from customer in // ... 
    let age = GetAge(customer.BirthDate) 
    where // ... 
select customer; 
+0

è possibile avere due dove clausole come questa? –

+0

no, non lo è. la query dovrebbe funzionare se si rimuove il secondo 'dove' –

+0

non è - aggiornato la mia risposta –