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!
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.
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]
à 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.
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.
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
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!
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()
.