Funzioni di database
Le funzioni di database sono equivalenti al database dei metodi C#. Una funzione di database può essere richiamata con zero o più parametri e calcola il risultato in base ai valori dei parametri. La maggior parte dei database, che usano SQL per l'esecuzione di query, supporta le funzioni del database. Pertanto, SQL generato dalla conversione di query di EF Core consente anche di richiamare le funzioni del database. I metodi C# non devono essere convertiti rigorosamente in funzioni di database in EF Core.
- Un metodo C# potrebbe non avere una funzione di database equivalente.
- Il metodo String.IsNullOrEmpty viene convertito in un controllo Null e un confronto con una stringa vuota nel database anziché in una funzione.
- Il metodo String.Equals(String, StringComparison) non ha un database equivalente perché il confronto tra stringhe non può essere rappresentato o simulato facilmente in un database.
- Una funzione di database potrebbe non avere un metodo C# equivalente. L'operatore
??
in C#, che non dispone di alcun metodo, viene convertito nellaCOALESCE
funzione nel database.
Tipi di funzioni di database
La generazione sql di EF Core supporta un subset di funzioni che possono essere usate nei database. Questa limitazione deriva dalla possibilità di rappresentare una query in LINQ per la funzione di database specificata. Inoltre, ogni database ha un supporto variabile delle funzioni di database, quindi EF Core fornisce un subset comune. Un provider di database è gratuito per estendere la generazione di EF Core SQL per supportare più modelli. Di seguito sono riportati i tipi di funzioni di database supportate da EF Core e identificano in modo univoco. Questi termini aiutano anche a comprendere quali traduzioni sono integrate con i provider EF Core.
Funzioni integrate e funzioni definite dall'utente
Le funzioni predefinite sono dotate di database predefinite, ma le funzioni definite dall'utente vengono definite in modo esplicito dall'utente nel database. Quando EF Core converte le query per usare le funzioni di database, usa funzioni predefinite per assicurarsi che la funzione sia sempre disponibile nel database. La distinzione delle funzioni predefinite è necessaria in alcuni database per generare correttamente SQL. Ad esempio, SqlServer richiede che ogni funzione definita dall'utente venga richiamata con un nome completo dello schema. Ma le funzioni predefinite in SqlServer non hanno uno schema. PostgreSQL definisce la funzione predefinita nello schema public
, ma può essere richiamata con nomi qualificati dallo schema.
Funzioni aggregate e scalari e con valori di tabella
- Le funzioni scalari accettano valori scalari, ad esempio numeri interi o stringhe, come parametri e restituiscono un valore scalare come risultato. Le funzioni scalari possono essere usate in qualsiasi punto di SQL in cui è possibile passare un valore scalare.
- Le funzioni di aggregazione accettano un flusso di valori scalari come parametri e restituiscono un valore scalare come risultato. Le funzioni di aggregazione vengono applicate all'intero set di risultati della query o a un gruppo di valori generati applicando l'operatore
GROUP BY
. - Le funzioni con valori di tabella accettano valori scalari come parametri e restituiscono un flusso di righe come risultato. Le funzioni con valori di tabella vengono usate come origine di tabella nella clausola
FROM
.
Funzioni senza parametri
Le funzioni senza parametri sono funzioni di database speciali che non hanno parametri e devono essere richiamate senza parentesi. Sono simili all'accesso a proprietà/campo in un'istanza in C#. Le funzioni senza parametri differiscono dalle funzioni senza parametro perché quest'ultima richiede parentesi vuote. Non esiste un nome speciale per le funzioni di database che richiedono sempre parentesi. Un altro subset di funzioni di database basato sul conteggio dei parametri è rappresentato da funzioni variadic. Le funzioni variadic possono accettare un numero variabile di parametri quando viene richiamato.
Mapping delle funzioni di database in EF Core
EF Core supporta tre modi diversi per eseguire il mapping tra funzioni C# e funzioni di database.
Mapping predefinito delle funzioni
Per impostazione predefinita, i provider EF Core forniscono mapping per varie funzioni predefinite sui tipi primitivi. Ad esempio, String.ToLower() viene convertito LOWER
in SqlServer. Questa funzionalità consente agli utenti di scrivere facilmente query in LINQ. In genere viene fornita una traduzione nel database che restituisce lo stesso risultato di ciò che la funzione C# fornisce sul lato client. A volte, per ottenere questo risultato, la traduzione effettiva potrebbe essere qualcosa di più complicato di una funzione di database. In alcuni scenari viene inoltre fornito la traduzione più appropriata anziché la semantica C# corrispondente. La stessa funzionalità viene usata anche per fornire traduzioni comuni per alcuni degli accessi ai membri C#. Ad esempio, String.Length viene convertito LEN
in SqlServer. Oltre ai provider, i writer di plug-in possono anche aggiungere traduzioni aggiuntive. Questa estendibilità è utile quando i plug-in aggiungono supporto per più tipi come tipi primitivi e vogliono tradurre i metodi su di essi.
Mapping EF.Functions
Poiché non tutte le funzioni di database hanno funzioni C# equivalenti, i provider EF Core dispongono di metodi C# speciali per richiamare determinate funzioni di database. Questi metodi vengono definiti come metodi di estensione EF.Functions
da usare nelle query LINQ. Questi metodi sono specifici del provider perché sono strettamente legati a funzioni di database specifiche. Pertanto, un metodo che funziona per un provider probabilmente non funzionerà per nessun altro provider. Inoltre, poiché l'intenzione di questi metodi è richiamare una funzione di database nella query tradotta, cercando di valutarle sul client genera un'eccezione.
Mapping delle funzioni definite dall'utente
Oltre ai mapping forniti dai provider EF Core, gli utenti possono anche definire il mapping personalizzato. Un mapping definito dall'utente estende la traduzione delle query in base alle esigenze dell'utente. Questa funzionalità è utile quando nel database sono presenti funzioni definite dall'utente, che l'utente vuole richiamare dalla query LINQ.