Entity Framework Code First prend-il en charge les procédures stockées?

112

J'ai regardé plusieurs présentations d'EF Code First et je n'ai pas vu comment EFCF fonctionne avec les procédures stockées.

Comment puis-je déclarer une méthode qui utilisera des sp? Puis-je passer une entité à une méthode qui appelle sp sans mapper manuellement les propriétés d'entité aux paramètres sp?

Aussi, que se passe-t-il si je change de modèle? Est-ce que cela ferait tomber mon sp en recréant la table à partir du modèle? Et qu'en est-il des déclencheurs?

Si ces éléments ne sont pas pris en charge, existe-t-il des plans pour les soutenir à l'avenir?

frennky
la source
5
La feuille de route EF indique qu'EF 6 prendra en charge les procédures stockées et les fonctions pour Code First. entityframework.codeplex.com/wikipage?title=Roadmap
frennky
Voir aussi: stackoverflow.com/questions/4873607/…
Nathan Koop

Réponses:

66

EDIT: Ma réponse originale pour EF4.1 (ci-dessous) est maintenant obsolète. Veuillez consulter la réponse ci-dessous de Diego Vega (qui travaille dans l'équipe EF chez Microsoft)!


@gsharp et Shawn Mclean: Où obtenez-vous ces informations? N'avez-vous toujours pas accès à l'ObjectContext sous-jacent?

IEnumerable<Customer> customers = 
    ((IObjectContextAdapter)this)
    .ObjectContext.ExecuteStoreQuery<Customer>("select * from customers");

Remplacez l'instruction "select" par un proc stocké, et c'est parti.

Quant à votre autre question: oui, malheureusement, vos sp seront écrasés. Vous devrez peut-être ajouter les instructions "CREATE PROCEDURE" dans votre code.

Pour EF 4.2:

var customers = context.Database.SqlQuery<Customer>("select * from customers")
anon
la source
Merci. Pourriez-vous m'indiquer quelques liens qui contiennent plus d'informations sur ce sujet.
frennky
1
Vous voudrez rechercher les trois fonctions Execute sur l'objet ObjectContext (ExecuteStoreQuery, ExecuteFunction et ExecuteStoreCommand).
Anon
J'ai mal compris la question. Je pensais qu'il voulait créer des SP sur une base de code.
gsharp
Vous pouvez remplacer Context.OnModelCreating et ajouter une logique personnalisée pour créer assez facilement des éléments de base de données tels que des processus stockés via du code. Pas idéal mais à la rigueur ça fera l'affaire.
Rick Strahl
Vous n'avez pas besoin du cast IObjectContextAdapter. Le DbContext peut gérer des sp ou des instructions SQL personnalisées à l'aide de l'objet Database intégré: context.Database.SqlQuery <Dummy> ("sp_GetDummy");
Steven K.
50

Mise à jour: à partir d'EF6, EF Code First prend en charge le mappage de procédure stockée pour les insertions, les mises à jour et les suppressions. Vous pouvez spécifier le mappage de procédure stockée lors de la création du modèle à l'aide de la méthode MapToStoredProcedures. Nous prenons également en charge l'échafaudage automatique des procédures stockées de base pour ces opérations. Voir la spécification des fonctionnalités ici .

Réponse originale: nous n'aurons pas de support pour le mappage des procédures stockées dans le modèle dans Code-First dans la première version, ni nous n'aurons un moyen de générer automatiquement des procédures stockées pour les opérations CRUD à partir de vos types. Ce sont des fonctionnalités que nous aimerions ajouter à l'avenir.

Comme cela a été mentionné dans ce fil, il est possible de revenir à ObjectContext mais DbContext fournit également de belles API pour exécuter des requêtes et des commandes SQL natives (par exemple DbSet.SqlQuery, DbContext.Database.SqlQuery et DbContext.Database.ExecuteSqlCommand). Les différentes versions de SqlQuery ont la même fonctionnalité de matérialisation de base qui existe dans EF4 (comme ExecuteStoreQuery: http://msdn.microsoft.com/en-us/library/dd487208.aspx ).

J'espère que cela t'aides.

plonger
la source
6
BTW, j'ai écrit un article de blog il y a quelques jours qui détaille comment utiliser ces méthodes pour appeler des procédures stockées, même des procédures stockées avec des paramètres de sortie: blogs.msdn.com/b/diego/archive/2012/01/10/… .
divega
3
Fin 2013, EF6 est toujours en développement. Attendre trois ans juste pour améliorer le support des sprocs, soupir.
DOK
1
@divega Existe-t-il une prise en charge fortement typée pour simplement sélectionner des valeurs à partir d'une procédure stockée - cette approche basée sur le code semble spécifique à la gestion de la durée de vie des objets? Plus précisément, pour les recherches complexes, à l'aide d'une procédure stockée spFooSearch avec un paramètre de sortie TotalRows.
John Zabroski
31
    public IList<Product> GetProductsByCategoryId(int categoryId)
    {
        IList<Product> products;

        using (var context = new NorthwindData())
        {
            SqlParameter categoryParam = new SqlParameter("@categoryID", categoryId);
            products = context.Database.SqlQuery<Product>("Products_GetByCategoryID @categoryID", categoryParam).ToList();
        }

        return products;
    }

    public Product GetProductById(int productId)
    {
        Product product = null;

        using (var context = new NorthwindData())
        {
            SqlParameter idParameter = new SqlParameter("@productId", productId);
            product = context.Database.SqlQuery<Product>("Product_GetByID @productId", idParameter).FirstOrDefault();
        }

        return product;
    }
marque
la source
8

Une solution plus sûre de type serait la suivante:

http://strugglesofacoder.blogspot.be/2012/03/calling-stored-procedure-with-entity.html

L'utilisation de cette classe est:

var testProcedureStoredProcedure = new TestProcedureStoredProcedure() { Iets = 5, NogIets = true };

var result = DbContext.Database.ExecuteStoredProcedure(testProcedureStoredProcedure);
Luc Bos
la source
Le lien n'est plus actif, mais voici l'archive: web.archive.org/web/20150430090848/http://www.lucbos.net/2012/…
Arturo Torres Sánchez
2

Pour .NET Core (EntityFrameworkCore), j'ai pu les faire fonctionner.

Ce n'est peut-être pas le plus soigné, mais cela fonctionne définitivement.

La migration pour ajouter la procédure stockée ressemble à ceci :

using Microsoft.EntityFrameworkCore.Migrations;
using System.Text;

namespace EFGetStarted.AspNetCore.NewDb.Migrations
{
    public partial class StoredProcedureTest : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("CREATE PROCEDURE GetBlogForAuthorName");
            sb.AppendLine("@authorSearch varchar(100)");
            sb.AppendLine("AS");
            sb.AppendLine("BEGIN");
            sb.AppendLine("-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.");
            sb.AppendLine("SET NOCOUNT ON;");
            sb.AppendLine("SELECT  Distinct Blogs.BlogId, Blogs.Url");
            sb.AppendLine("FROM Blogs INNER JOIN");
            sb.AppendLine("Posts ON Blogs.BlogId = Posts.BlogId INNER JOIN");
            sb.AppendLine("PostsAuthors ON Posts.PostId = PostsAuthors.PostId Inner JOIN");
            sb.AppendLine("Authors on PostsAuthors.AuthorId = Authors.AuthorId");
            sb.AppendLine("Where Authors.[Name] like '%' + @authorSearch + '%'");
            sb.AppendLine("END");

            migrationBuilder.Sql(sb.ToString());
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql("DROP PROCEDURE GetBlogForAuthorName");
        }
    }
}

Je pourrais alors l'appeler avec le code suivant :

var blogs = _context.Blogs.FromSql("exec GetBlogForAuthorName @p0", "rod").Distinct();

Plus tard, j'ai essayé d'obtenir certaines des données associées (une à plusieurs données de relation, par exemple le contenu de la publication) et le blog est revenu avec le contenu de la publication rempli comme prévu.

HockeyJ
la source