web-dev-qa-db-fra.com

Comment exécuter SqlQuery avec Entity Framework Core 2.1?

Dans Entity Framework 6, je peux exécuter une requête SQL brute sur la base de données à l'aide de la commande suivante:

IEnumerable<string> Contact.Database.SqlQuery<string>("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10");

Sur un nouveau projet, j'essaie d'utiliser Entity Framework Core 2.1. J'ai besoin d'exécuter une requête SQL brute. Pendant la recherche sur Google, je peux voir que l’extension SqlQuery a été remplacée par FromSql. Cependant, FromSql n'existe que sur le DbSet<> pas sur le DbContext.Database.

Comment puis-je exécuter FromSql en dehors du DbSet<>? La méthode FromSql n'existe pas sur l'objet de base de données DbContext.Database.FromSql<>.

12
Junior

Je peux voir que l'extension SqlQuery a été changée en FromSql

Mais la nouvelle méthode FromSql est plus restrictive que SqlQuery. La documentation de cette méthode explique qu'il existe des limitations telles que:

Les requêtes SQL ne peuvent être utilisées que pour renvoyer les types d'entité qui font partie de votre modèle. Notre carnet de commandes a été amélioré en permettre le renvoi des types ad-hoc à partir de requêtes SQL brutes .

La requête SQL doit renvoyer des données pour toutes les propriétés de l'entité ou du type de requête.

[...]

Donc, dans votre cas, la requête SQL que vous utilisez est la suivante:

SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10

Comme le dit la documentation, vous ne pouvez utiliser que FromSql avec une entité ou un type de requête . Votre requête SQL ne renvoie pas toutes les données de votre entité définies dans votre modèle, mais elle ne renvoie qu'une colonne de votre entité. Soit dit en passant, une nouvelle fonctionnalité est introduite dans EF Core 2.1, disponible dans la version candidate depuis le 7 mai 2018. Microsoft déclare:

EF Core 2.1 RC1 est une version "en direct". Cela signifie qu'une fois que vous avez vérifié que votre application fonctionnait correctement avec RC1, vous pouvez l'utiliser en production et obtenir une assistance technique de Microsoft, mais vous devez tout de même passer à la version finale stable une fois qu'elle sera disponible. .

Utilisation de FromSql sur le type de requête

Qu'est-ce qu'un type de requête :

Un modèle EF Core peut désormais inclure des types de requête. Contrairement aux types d'entité, les types de requête n'ont pas de clé définie et ne peuvent pas être insérés, supprimés ou mis à jour (c'est-à-dire qu'ils sont en lecture seule), mais ils peuvent être retournés directement par des requêtes. Certains scénarios d'utilisation pour les types de requête sont les suivants: mappage sur des vues sans clé primaire, mappage sur des tables sans clé primaire, mappage sur des requêtes définies dans le modèle, servant de type de retour pour les requêtes FromSql ()

Si vous souhaitez utiliser une fonctionnalité de type de requête avec votre texte SQL, définissez d'abord une classe, appelons-la MySuperClass:

public class MySuperClass
{
    public string Title { get; set; }
}

Ensuite, dans votre classe DbContext, définissez une propriété de type DbQuery<MySuperClass> Comme ci-dessous:

public DbQuery<MySuperClass> MySuperQuery { get; set; }

Enfin, vous pouvez utiliser FromSql comme ci-dessous:

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;

Je ne veux pas utiliser DbQuery<T>

Si vous ne voulez pas utiliser DbQuery<T> Et ne voulez pas définir une classe qui ne contient qu'une propriété, vous pouvez utiliser ExecuteSqlCommandAsync comme @ vivek nuna l’a fait dans sa réponse (sa réponse est partiellement correcte). Mais vous devez savoir que la valeur renvoyée par cette méthode est le nombre de lignes affectées par votre requête. De plus, vous devez définir votre titre en tant que paramètre de sortie afin que votre requête soit une procédure stockée. Utilisez ExecuteSqlCommandAsync ou ExecuteSqlCommand et lisez ensuite le paramètre de sortie que vous avez transmis lors de l'appel de la méthode.

Une manière plus simple de ne pas créer de procédure stockée et donc de ne pas utiliser ExecuteSqlCommandAsync ou ExecuteSqlCommand consiste à utiliser le code suivant:

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 
    }
}  

Vous pouvez faire de cette logique une méthode d'assistance qui recevra votre requête SQL et renverra les données souhaitées. Mais je vous recommande d’utiliser Dapper.Net qui contient de nombreuses méthodes utiles qui vous aideront à gérer facilement le format RAW SQL comme nous le faisons ci-dessus et à partager la connexion smae avec DbContext.

17
CodeNotFound

Vous pouvez utiliser la méthode ExecuteSqlCommandAsync définie dans RelationalDatabaseFacadeExtensions class of Microsoft.EntityFrameworkCore.Relational Assemblage de la manière suivante.

_databaseContext.Database.ExecuteSqlCommandAsync(<Your parameters>)
3
vivek nuna