In Entity Framework è possibile verificare l'esistenza di una tabella in questo modo:
bool exists = context.Database
.SqlQuery<int?>(@"
SELECT 1 FROM sys.tables AS T
INNER JOIN sys.schemas AS S ON T.schema_id = S.schema_id
WHERE S.Name = 'SchemaName' AND T.Name = 'TableName'")
.SingleOrDefault() != null;
Sto usando EF Core 2.1 e il metodo SqlQuery
non esiste.
Quale sarebbe il modo giusto per verificare se esiste o meno un tavolo? Idealmente senza cercare di accedere alla tabella e assumendo che non esiste se viene lanciata un'eccezione.
EDIT: la mia implementazione finale
public bool TableExists(string tableName)
{
return TableExists("dbo", tableName);
}
public bool TableExists(string schema, string tableName)
{
var connection = Context.Database.GetDbConnection();
if (connection.State.Equals(ConnectionState.Closed))
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = @"
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = @Schema
AND TABLE_NAME = @TableName";
var schemaParam = command.CreateParameter();
schemaParam.ParameterName = "@Schema";
schemaParam.Value = schema;
command.Parameters.Add(schemaParam);
var tableNameParam = command.CreateParameter();
tableNameParam.ParameterName = "@TableName";
tableNameParam.Value = tableName;
command.Parameters.Add(tableNameParam);
return command.ExecuteScalar() != null;
}
}
Esiste ExecuteSqlCommand
.
context.Database.ExecuteSqlCommand("...")
Tuttavia, è limitato alla restituzione di un intero che indica il numero di righe interessate. Nessuna riga viene influenzata se stai facendo una SELECT
, quindi non funziona davvero per quello che vuoi.
C'è anche FromSql
, ma funziona solo sulle tabelle, non a livello di database:
context.TableName.FromSql("SELECT ...")
Per quello che stai facendo, un'opzione migliore è ottenere DbConnection
da EF e creare il tuo DbCommand
. Questo restituisce ciò che ti aspetteresti:
var conn = context.Database.GetDbConnection();
if (conn.State.Equals(ConnectionState.Closed)) await conn.OpenAsync();
using (var command = conn.CreateCommand()) {
command.CommandText = @"
SELECT 1 FROM sys.tables AS T
INNER JOIN sys.schemas AS S ON T.schema_id = S.schema_id
WHERE S.Name = 'SchemaName' AND T.Name = 'TableName'";
var exists = await command.ExecuteScalarAsync() != null;
}
Una parola di avviso qui: non inserire il DbConnection
ottenuto da GetDbConnection()
in un'istruzione using
, o chiuderlo quando hai finito. Quella connessione viene utilizzata per la durata di tale istanza di DbContext
. Quindi se lo chiudi, qualsiasi richiesta successiva fatta da EF fallirà. È anche possibile che fosse già aperto prima del tuo codice, motivo per cui ho messo un test lì dentro per vedere se è chiuso prima di chiamare OpenAsync()
.