web-dev-qa-db-fra.com

Est-il possible d'exécuter SQL natif avec un framework d'entité?

J'essaie de rechercher un champ XML dans une table, cela n'est pas pris en charge avec EF.

Sans utiliser Ado.net pur, il est possible d'avoir un support SQL natif avec EF?

65
user80855

Pour .NET Framework version 4 et supérieure: utilisez ObjectContext.ExecuteStoreCommand() si votre requête ne renvoie aucun résultat et utilisez ObjectContext.ExecuteStoreQuery si votre requête renvoie des résultats.

Pour les versions précédentes de .NET Framework, voici un exemple illustrant ce qu'il faut faire. Remplacez ExecuteNonQuery () si nécessaire si votre requête renvoie des résultats.

static void ExecuteSql(ObjectContext c, string sql)
{
    var entityConnection = (System.Data.EntityClient.EntityConnection)c.Connection;
    DbConnection conn = entityConnection.StoreConnection;
    ConnectionState initialState = conn.State;
    try
    {
        if (initialState != ConnectionState.Open)
            conn.Open();  // open connection if not already open
        using (DbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();
        }
    }
    finally
    {
        if (initialState != ConnectionState.Open)
            conn.Close(); // only close connection if not initially open
    }
}
72
Justin Grant

En utilisant Entity Framework 5.0 vous pouvez utiliser ExecuteSqlCommand pour exécuter des instructions SQL pures multi-lignes/multi-commandes. De cette façon, vous n'aurez pas besoin de fournir d'objet de sauvegarde pour stocker la valeur retournée puisque la méthode retourne un int (le résultat retourné par la base de données après l'exécution de la commande).

Échantillon:

context.Database.ExecuteSqlCommand(@
"-- Script Date: 10/1/2012 3:34 PM  - Generated by ExportSqlCe version 3.5.2.18
SET IDENTITY_INSERT [Students] ON;

INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (12,N'First Name',N'SecondName',{ts '1988-03-02 00:00:00.000'},N'RUA 19 A, 60',N'MORADA DO VALE',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3346-7125',NULL,NULL,{ts '2011-06-04 21:25:26.000'},2,1);

INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (13,N'FirstName',N'LastName',{ts '1976-04-12 00:00:00.000'},N'RUA 201, 2231',N'RECANTO FELIZ',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3341-6892',NULL,NULL,{ts '2011-06-04 21:38:38.000'},2,1);
");

Pour en savoir plus, jetez un œil ici: Entity Framework Code First: Exécution de fichiers SQL lors de la création de la base de données

24

Pour Entity Framework 5 utilisez context.Database.SqlQuery.

Et pour Entity Framework 4 utilisez context.ExecuteStoreQuery le code suivant:

 public string BuyerSequenceNumberMax(int buyerId)
    {
        string sequenceMaxQuery = "SELECT TOP(1) btitosal.BuyerSequenceNumber FROM BuyerTakenItemToSale btitosal " +
                                  "WHERE btitosal.BuyerID =  " + buyerId +
                                  "ORDER BY  CONVERT(INT,SUBSTRING(btitosal.BuyerSequenceNumber,7, LEN(btitosal.BuyerSequenceNumber))) DESC";

        var sequenceQueryResult = context.Database.SqlQuery<string>(sequenceMaxQuery).FirstOrDefault();

        string buyerSequenceNumber = string.Empty;

        if (sequenceQueryResult != null)
        {
            buyerSequenceNumber = sequenceQueryResult.ToString();
        }

        return buyerSequenceNumber;
    }

Pour renvoyer une liste, utilisez le code suivant:

 public List<PanelSerialList> PanelSerialByLocationAndStock(string locationCode, byte storeLocation, string itemCategory, string itemCapacity, byte agreementType, string packageCode)
 {
       string panelSerialByLocationAndStockQuery = "SELECT isws.ItemSerialNo,  im.ItemModel " +
        "FROM Inv_ItemMaster im   " +
        "INNER JOIN  " +
        "Inv_ItemStockWithSerialNoByLocation isws  " +
        "   ON im.ItemCode = isws.ItemCode   " +
        "       WHERE isws.LocationCode = '" + locationCode + "' AND  " +
        "   isws.StoreLocation = " + storeLocation + " AND  " +
        "   isws.IsAvailableInStore = 1 AND " +
        "   im.ItemCapacity = '" + itemCapacity + "' AND " +
        "   isws.ItemSerialNo NOT IN ( " +
        "           Select sp.PanelSerialNo From Special_SpecialPackagePriceForResale sp  " +
        "           Where sp.PackageCode = '" + packageCode + "' )";


    return context.Database.SqlQuery<PanelSerialList>(panelSerialByLocationAndStockQuery).ToList();


}
17
Md. Nazrul Islam

Depuis .NET 4, vous pouvez utiliser la méthode ExecuteStoreQuery :

var list = myDBEntities.ExecuteStoreQuery<MyClass>(MyClass.sql);

où myDBEntities est hérité d'ObjectContext.

class MyClass
{
    /* You can change query to more complicated, e.g. with joins */
    public const string sql = @"select [MyTable].[MyField] from [MyTable]";
    public string MyField { get; set; }
}

Notez que MyTable est le vrai nom de la table, pas la classe EF.

16
Andrii Nemchenko

Rester simple

using (var context = new MyDBEntities())
{
    var m = context.ExecuteStoreQuery<MyDataObject>("Select * from Person", string.Empty);
    //Do anything you wonna do with 
    MessageBox.Show(m.Count().ToString());
}
3
ELTEE
public class RaptorRepository<T>
    where T : class
{
    public RaptorRepository()
        : this(new RaptorCoreEntities())
    {
    }

    public RaptorRepository(ObjectContext repositoryContext)
    {
        _repositoryContext = repositoryContext ?? new RaptorCoreEntities();
        _objectSet = repositoryContext.CreateObjectSet<T>();
    }

    private ObjectContext _repositoryContext;
    private ObjectSet<T> _objectSet;
    public ObjectSet<T> ObjectSet
    {
        get
        {
            return _objectSet;
        }
    }


    public void DeleteAll()
    {
        _repositoryContext
            .ExecuteStoreCommand("DELETE " + _objectSet.EntitySet.ElementType.Name);
    }
}
2
Nirosh

Alors que dire de tout ça en 2017? Des consultations de 80k suggèrent que l'exécution d'une requête SQL dans EF est quelque chose que beaucoup de gens veulent faire. Mais pourquoi? Pour quel bénéfice?

Justin, un gourou avec 20 fois ma réputation, dans la réponse acceptée nous donne une méthode statique qui ressemble ligne par ligne comme l'équivalent ADO code. Assurez-vous de bien le copier car il y en a quelques-uns) subtilités pour ne pas se tromper. Et vous êtes obligé de concaténer votre requête avec vos paramètres d'exécution car il n'y a aucune disposition pour les paramètres appropriés. Ainsi, tous les utilisateurs de cette méthode construiront leur SQL avec des méthodes de chaîne (fragile, non testable, injection sql), et aucun d'entre eux ne fera l'objet de tests unitaires.

Les autres réponses ont les mêmes défauts, seulement plus. SQL enterré entre guillemets. Opportunités d'injection SQL largement dispersées. Chers pairs, c'est un comportement absolument sauvage. Si ce C # était généré, il y aurait une guerre des flammes. Nous n'acceptons même pas de générer du HTML de cette façon, mais en quelque sorte, c'est OK pour SQL. Je sais que les paramètres de requête n'étaient pas le sujet de la question, mais nous copions et réutilisons ce que nous voyons, et les réponses ici sont à la fois des modèles et des témoignages de ce que font les gens.

EF a-t-il fait fondre notre cerveau? EF ne veut pas que vous utilisiez SQL, alors pourquoi utiliser EF pour faire SQL.

Vouloir utiliser SQL pour parler à une base de données relationnelle est une impulsion saine et normale chez les adultes. QueryFirst montre comment cela pourrait être fait intelligemment, votre sql dans un fichier .sql, validé lors de la frappe, avec intellisense pour les tables et colonnes. L'encapsuleur C # est généré par l'outil, de sorte que vos requêtes deviennent détectables dans le code, avec intellisense pour vos entrées et résultats. Une frappe forte de bout en bout, sans jamais avoir à vous soucier d'un type. Plus besoin de se souvenir d'un nom de colonne ou de son index. Et il existe de nombreux autres avantages ... La tentation de concaténer est supprimée. La possibilité de mal gérer vos connexions également. Toutes vos requêtes et le code qui y accède sont testés en continu par rapport à votre base de données de développement. Les modifications de schéma dans votre base de données s'affichent sous forme d'erreurs de compilation dans votre application. Nous générons même une méthode d'auto-test dans le wrapper, afin que vous puissiez tester de nouvelles versions de votre application par rapport aux bases de données de production existantes, plutôt que d'attendre que le téléphone sonne. Quelqu'un a encore besoin de convaincre?

Avertissement: j'ai écrit QueryFirst :-)

0
bbsimonbb