Pouvez-vous créer des vues sql / procédure stockée en utilisant Entity Framework 4.1 Code first approach

Entity Framework 4.1 le Premier Code fonctionne très bien à créer des tables et des relations. Est-il possible de créer des vues sql ou une procédure stockée en utilisant la première approche de Code? Tout conseil à ce sujet sera très apprécié. Merci beaucoup!

42
demandé sur Ryan The Leach 2011-10-06 00:55:36

7 réponses

EF code-first approach s'attend à ce qu'il n'y ait aucune logique dans la base de données. Cela signifie pas de procédures stockées et pas de vues de base de données. En raison de cette approche code-premier ne fournit aucun mécanisme pour générer de telles constructions automatiquement pour vous. Comment pourrait-il le faire si cela signifie générer de la logique?

vous devez les créer vous-mêmes dans initialiseur de base de données personnalisé par l'exécution manuelle des scripts de création. Je ne pense pas que ce SQL personnalisé les constructions peuvent être gérées par des migrations SQL.

9
répondu Ladislav Mrnka 2017-05-23 12:10:54

nous supportons les procédures stockées dans nos premières Migrations de code-cadre D'entité. Notre approche consiste à créer un dossier pour le conserver .fichiers sql (~/Sql / par exemple). Créer. les fichiers sql dans le dossier pour la création et l'abandon de la procédure stockée. Par exemple: Create_sp_DoSomething.sql et Drop_sp_DoSomething . Parce que le SQL s'exécute dans un lot et que CREATE PROCEDURE.. doit être la première instruction dans un lot, faire de CREATE PROCEDURE... la première instruction dans le fichier. Aussi, ne mettez pas GO après le DROP... . Ajouter un fichier à votre projet, si vous n'avez pas déjà un. Faites glisser le .les dossiers de sql de l'Explorateur de solution dans la vue de dossiers du créateur de ressources. Maintenant, créez une migration vide ( Add-Migration SomethingMeaningful_sp_DoSomething ) et utilisez:

namespace MyApplication.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class SomethingMeaningful_sp_DoSomething : DbMigration
    {
        public override void Up()
        {
            this.Sql(Properties.Resources.Create_sp_DoSomething);
        }

        public override void Down()
        {
            this.Sql(Properties.Resources.Drop_sp_DoSomething);
        }
    }
}

~/Sql/Create_sp_DoSomething.sql

CREATE PROCEDURE [dbo].[sp_DoSomething] AS
BEGIN TRANSACTION
-- Your stored procedure here
COMMIT TRANSACTION
GO

~/Sql/Drop_sp_DoSomething.sql

DROP PROCEDURE [dbo].[sp_DoSomething]
72
répondu Carl G 2013-03-02 07:17:49

à première vue j'aime vraiment l'approche de Carl G, mais il implique beaucoup d'interaction manuelle. Dans mon scénario, je laisse toujours tomber toutes les procédures stockées, les vues... et les recréer chaque fois qu'il y a un changement dans la base de données. De cette façon, nous sommes sûrs que tout est à jour avec la dernière version.

Loisirs qui se passe par la définition de la suite de l'Initialiseur:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());

alors notre méthode de semence sera appelée à chaque fois qu'il y a une migration prêt

protected override void Seed(DeploymentLoggingContext context)
    {
        // Delete all stored procs, views
        foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sql\Seed"), "*.sql"))
        {
            context.Database.ExecuteSqlCommand(File.ReadAllText(file), new object[0]);
        }

        // Add Stored Procedures
        foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sql\StoredProcs"), "*.sql"))
        {
            context.Database.ExecuteSqlCommand(File.ReadAllText(file), new object[0]);
        }
    }
Les instructions

SQL sont stockées dans *.fichiers sql pour une édition facile. Assurez-vous que vos fichiers ont "Build Action" défini à "Content" et "Copy to Output Directory" défini à "Copy Always". Nous recherchons les dossiers et exécutons tous les scripts à l'intérieur. N'oubliez pas d'exclure les instructions "GO" dans votre SQL car elles ne peuvent pas être exécutées avec ExecuteSqlCommand().

la disposition actuelle de mon répertoire est la suivante:

Projet.DAL

+ Migrations

+ Sql

++

+ + + dbo.cleanDb.sql

++ StoredProcs

+ + + dbo.sp_GetSomething.sql

Maintenant vous avez juste besoin de laisser tomber les procédures stockées supplémentaires dans le dossier et tout sera mis à jour de manière appropriée.

22
répondu emp 2014-10-28 13:16:51

il semble être mal documenté mais il semble que vous pouvez maintenant faire quelques manipulations de procédure stockées en utilisant AlterStoredProcedure , CreateStoredProcedure , DropStoredProcedure , MoveStoredProcedure , renamestoredprocedure dans Entity Framework 6. Je ne les ai pas encore essayés donc je ne peux pas encore donner un exemple de comment les utiliser.

10
répondu bbodenmiller 2014-11-10 09:22:38

pour développer sur la réponse de bbodenmiller , dans le cadre D'Entity 6, La classe de migration DB a des méthodes telles que AlterStoredProcedure qui permettent de modifier les procédures stockées sans avoir à tomber tout le chemin vers le SQL brut.

voici un exemple de méthode de migration Up() qui modifie une procédure stockée sur un serveur SQL appelé EditItem qui prend trois paramètres de type int , nvarchar(50) , et smallmoney , respectivement:

public partial class MyCustomMigration : DbMigration
{
    public override void Up()
    {
        this.AlterStoredProcedure("dbo.EditItem", c => new
        {
            ItemID = c.Int(),
            ItemName = c.String(maxLength:50),
            ItemCost = c.Decimal(precision: 10, scale: 4, storeType: "smallmoney")
        }, @" (Stored procedure body SQL goes here) "   
    }

    //...
}

sur ma machine, ce script de migration produit le SQL suivant:

ALTER PROCEDURE [dbo].[EditItem]
    @ItemID [int],
    @ItemName [nvarchar](50),
    @ItemCost [smallmoney]
AS
BEGIN
    (Stored procedure body SQL goes here)
END
9
répondu Jon Schneider 2017-05-23 12:34:59

la conception de l'emp fonctionne comme un champion! J'utilise son pattern mais j'ai aussi mappé les procédures stockées dans ma classe DbContext qui permet simplement d'appeler ces méthodes de contexte au lieu d'utiliser SqlQuery() et d'appeler les procédures directement depuis mon dépôt. Comme les choses peuvent devenir un peu velues quand l'application se développe, j'ai créé une vérification dans ma méthode de Seed qui fait en sorte que le nombre réel de paramètres de procédure stockés correspondent jusqu'au nombre de paramètres sur la méthode de mappage. J'ai aussi mise à jour de la boucle de dépose emp mentionné. Au lieu d'avoir à maintenir un dossier/fichier séparé pour les déclarations de goutte, je lis simplement la première ligne de chaque fichier sql et remplace CREATE par DROP (assurez-vous que la première ligne est toujours juste CREATE PROCEDURE ProcName ). De cette façon, toutes les procédures dans mon dossier StoredProcs sont abandonnées et recréées chaque fois que Update-Database est lancé. Le drop est également enveloppé dans un bloc try-catch au cas où la procédure est nouvelle. Pour le paramètre de procédure count to travailler, vous aurez besoin de vous assurer que vous envelopper un BEGIN/END bloc autour de votre tsql depuis chaque ligne du fichier est lu pour commencer. Assurez-vous également que chaque paramètre sp est sur la nouvelle ligne.

        // Drop Stored Procs
        foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\DataContext\SiteMigrations\StoredProcs"), "*.sql"))
        {
            // Try to drop proc if its already created
            // Without this, for new procs, seed method fail on trying to delete
            try
            {
                StreamReader reader = new StreamReader(file);
                // Read first line of file to create drop command (turning CREATE [dbo].[TheProc] into DROP [dbo].[TheProc])
                string dropCommand = reader.ReadLine().Replace("CREATE", "DROP");

                context.Database.ExecuteSqlCommand(dropCommand, new object[0]);
            }
            catch { }

        }

        // Add Stored Procs
        foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\DataContext\SiteMigrations\StoredProcs"), "*.sql"))
        {
            // File/Proc names must match method mapping names in DbContext
            int lastSlash = file.LastIndexOf('\');
            string fileName = file.Substring(lastSlash + 1);
            string procName = fileName.Substring(0, fileName.LastIndexOf('.'));

            // First make sure proc mapping in DbContext contain matching parameters.  If not throw exception.
            // Get parameters for matching mapping
            MethodInfo mi = typeof(SiteContext).GetMethod(procName);

            if (mi == null)
            {
                throw new Exception(String.Format("Stored proc mapping for {0} missing in DBContext", procName));
            }

            ParameterInfo[] methodParams = mi.GetParameters();
            // Finished getting parameters

            // Get parameters from stored proc
            int spParamCount = 0;
            using (StreamReader reader = new StreamReader(file))
            {
                string line;                    
                while ((line = reader.ReadLine()) != null) 
                {
                    // If end of parameter section, break out
                    if (line.ToUpper() == "BEGIN")
                    {
                        break;
                    }
                    else
                    {
                        if (line.Contains("@"))
                        {
                            spParamCount++;
                        }
                    }                        
                }
            }
            // Finished get parameters from stored proc

            if (methodParams.Count() != spParamCount)
            {
                string err = String.Format("Stored proc mapping for {0} in DBContext exists but has {1} parameter(s)" +
                    " The stored procedure {0} has {2} parameter(s)", procName, methodParams.Count().ToString(), spParamCount.ToString());
                throw new Exception(err);
            }
            else
            {
                context.Database.ExecuteSqlCommand(File.ReadAllText(file), new object[0]);
            }
        }

Profitez-en!

2
répondu Natas0007 2014-10-23 20:34:50

comme Ladislav l'a souligné, DbContext en général a tendance à minimiser la logique dans la base de données, mais il est possible d'exécuter SQL personnalisé en utilisant context.Database.ExecuteSqlCommand() ou context.Database.SqlQuery() .

1
répondu Mark Stafford - MSFT 2013-08-16 14:55:53