In Entity Framework 6, posso eseguire una query SQL raw sul database usando il seguente comando:
IEnumerable<string> Contact.Database.SqlQuery<string>("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10");
In un nuovo progetto, sto cercando di utilizzare Entity Framework Core 2.1. Ho bisogno di eseguire query SQL raw. Durante la ricerca su google, posso vedere che l'estensione SqlQuery
stata modificata in FromSql
. Tuttavia, FromSql
esiste solo su DbSet<>
non su DbContext.Database
.
Come posso eseguire FromSql
all'esterno di DbSet<>
? Il metodo FromSql
non esiste sull'oggetto database DbContext.Database.FromSql<>
.
Vedo che l'estensione SqlQuery è stata modificata in FromSql
Ma il nuovo metodo FromSql
è più restrittivo di SqlQuery
. La documentazione di quel metodo spiega che esistono alcune limitazioni come:
Le query SQL possono essere utilizzate solo per restituire i tipi di entità che fanno parte del modello . C'è un miglioramento nel nostro backlog per abilitare la restituzione di tipi ad-hoc da query SQL non elaborate .
La query SQL deve restituire i dati per tutte le proprietà dell'entità o del tipo di query .
[...]
Quindi nel tuo caso la query SQL che stai utilizzando è la seguente:
SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10
Come dice la documentazione, puoi utilizzare FromSql
solo con entità o tipo di query . La tua query SQL non restituisce tutti i dati della tua entità definiti nel tuo modello ma restituisce solo una colonna della tua entità. Tra l'altro, una nuova funzionalità è introdotta in EF Core 2.1, che è in Release Candidate dal 7 maggio 2018. Microsoft dichiara:
EF Core 2.1 RC1 è una versione "da vivere", il che significa che una volta verificato che l'applicazione funziona correttamente con RC1, è possibile utilizzarla in produzione e ottenere supporto da Microsoft, ma si dovrebbe comunque aggiornare alla versione stabile definitiva una volta € ™ s disponibile.
Che cos'è un tipo di query :
Un modello EF Core ora può includere tipi di query. A differenza dei tipi di entità, i tipi di query non hanno le chiavi definite su di essi e non possono essere inseriti, eliminati o aggiornati (ovvero sono di sola lettura), ma possono essere restituiti direttamente dalle query. Alcuni degli scenari di utilizzo per i tipi di query sono: associazione a viste senza chiavi primarie, associazione a tabelle senza chiavi primarie, associazione a query definite nel modello, che funge da tipo di ritorno per le query FromSql ()
Se vuoi usare la funzione di tipo di query con il tuo testo SQL, devi prima definire una classe, MySuperClass
:
public class MySuperClass
{
public string Title { get; set; }
}
Quindi nella classe DbContext
definita una proprietà di tipo DbQuery<MySuperClass>
come di seguito:
public DbQuery<MySuperClass> MySuperQuery { get; set; }
Finalmente puoi usare FromSql
su di esso come di seguito:
var result = context.MySuperQuery.FromSql("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10").ToList().First();
var title = result.Title;
DbQuery<T>
Se non si desidera utilizzare DbQuery<T>
e non si desidera definire una classe che contiene solo una proprietà, è possibile utilizzare ExecuteSqlCommandAsync
come ha fatto @ vivek nuna nella sua risposta (la sua risposta è parzialmente corretta). Ma devi sapere che il valore restituito da quel metodo è il numero di righe interessate dalla tua query. Inoltre devi mettere il tuo titolo come parametro di output in modo da rendere la tua query una stored procedure. Utilizzare ExecuteSqlCommandAsync
o ExecuteSqlCommand
e quindi leggere il parametro di output passato quando si chiama il metodo.
Un modo più semplice senza creare una procedura memorizzata, quindi, non utilizzando ExecuteSqlCommandAsync
o ExecuteSqlCommand
è il seguente codice:
using (var context = new MyDbContext())
{
var conn = context.Database.GetDbConnection();
await conn.OpenAsync();
var command = conn.CreateCommand();
const string query = "SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10";
command.CommandText = query;
var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
var title = reader.GetString(0);
// Do whatever you want with title
}
}
È possibile rendere questa logica un metodo di supporto che rileverà la query SQL e restituirà i dati desiderati. Ma ti consiglio di usare Dapper.Net che contiene molti metodi di aiuto che ti aiuteranno a gestire facilmente con SQL RAW come facciamo sopra e condividendo anche la connessione DbContext
con DbContext
.