Можете ли вы создавать представления sql / хранимую процедуру с использованием Entity Framework 4.1 Первый подход к коду
Entity Framework 4.1 Code First отлично работает с созданием таблиц и отношений. Возможно ли создать sql-представление или хранимую процедуру с использованием первого подхода Code? Любые указатели на это будут высоко оценены. Большое спасибо!
- Завершение кода PHP NetBeans
- Как получить «кодовое обозначение» gdb на OSX?
- Код C ++ в файлах заголовков
- Отладчик Visual Studio - отображение целочисленных значений в шестнадцатеричном виде
- Отключение автоматического форматирования в Visual Studio
- Генерировать различные случайные числа в C #
- Как определить неиспользуемые определения css
- Как испускать и выполнять байт-код Java во время выполнения?
EF-кодовый подход предполагает, что в базе данных нет никакой логики. Это означает отсутствие хранимых процедур и представлений базы данных. Из-за этого подхода, основанного на кодах, не предоставляется никакого механизма для создания таких конструкций автоматически для вас. Как это можно сделать, если это означает создание логики?
Вы должны создать их в пользовательском инициализаторе базы данных вручную, выполнив скрипты создания. Я не думаю, что эти пользовательские SQL-конструкции могут обрабатываться посредством миграции SQL.
Мы поддерживаем хранимые процедуры в First Entity Framework Code First Migrations. Наш подход заключается в создании некоторой папки для хранения файлов .sql (например, ~ / Sql /). Создайте файлы .sql в папке для создания и удаления хранимой процедуры. Например, Create_sp_DoSomething.sql
и Drop_sp_DoSomething
. Поскольку SQL работает в пакете и CREATE PROCEDURE..
должен быть первым оператором в пакете, сделать CREATE PROCEDURE...
первым оператором в файле. Кроме того, не ставьте GO
после DROP...
Добавьте файл ресурсов в свой проект, если у вас его еще нет. Перетащите файлы .sql из проводника решений в представление «Файлы» конструктора ресурсов. Теперь создайте пустую миграцию ( Add-Migration SomethingMeaningful_sp_DoSomething
) и используйте:
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]
На первый взгляд мне очень нравится подход Carl G, но это связано с большим количеством ручного взаимодействия. В моем сценарии я всегда отбрасываю все хранимые процедуры, представления … и воссоздает их всякий раз, когда в базе данных происходит изменение. Таким образом, мы уверены, что все обновлено с последней версией.
Отдых происходит, устанавливая следующий Инициализатор:
Database.SetInitializer(new MigrateDatabaseToLatestVersion());
Тогда наш метод семени будет вызван, когда будет готовность к миграции
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]); } }
Заявления SQL хранятся в файлах * .sql для удобного редактирования. Убедитесь, что ваши файлы имеют «Build Action», установленный в «Content» и «Copy to Output Directory», установленном в «Copy Always». Мы просматриваем папки и выполняем все скрипты внутри. Не забудьте исключить инструкции «GO» в SQL, потому что они не могут быть выполнены с помощью ExecuteSqlCommand ().
Мой текущий каталог выглядит следующим образом:
Project.DAL
+ Миграции
+ Sql
++ Seed
+++ dbo.cleanDb.sql
++ StoredProcs
+++ dbo.sp_GetSomething.sql
Теперь вам просто нужно отбросить дополнительные хранимые процедуры в папке, и все будет обновлено соответствующим образом.
Как представляется, он плохо документирован, однако теперь вы можете выполнять некоторые манипуляции с хранимой процедурой, используя AlterStoredProcedure , CreateStoredProcedure , DropStoredProcedure , MoveStoredProcedure , RenameStoredProcedure в Entity Framework 6. Я еще не пробовал их, но пока не могу привести пример того, как используй их.
Чтобы расширить ответ bbodenmiller , в Entity Framework 6 class DbMigration имеет такие методы, как AlterStoredProcedure, которые позволяют изменять хранимые процедуры без необходимости полностью отбрасывать исходный SQL.
Ниже приведен пример метода миграции Up()
который изменяет существующую хранимую процедуру SQL Server с именем EditItem, которая принимает три параметра типа int
, nvarchar(50)
и smallmoney
, соответственно:
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) " } //... }
На моей машине этот скрипт миграции создает следующий SQL:
ALTER PROCEDURE [dbo].[EditItem] @ItemID [int], @ItemName [nvarchar](50), @ItemCost [smallmoney] AS BEGIN (Stored procedure body SQL goes here) END
Дизайн emp работает как чемпион! Я использую его шаблон, но я также сопоставляю хранимые процедуры внутри моего classа DbContext, который позволяет просто называть эти контекстные методы вместо использования SqlQuery () и вызывать процедуры непосредственно из моего репозитория. По мере того, как приложение становится немного волосатым, когда приложение растет, я создал проверку в моем методе Seed, чтобы убедиться, что фактическое количество параметров хранимой процедуры соответствует счету параметров метода сопоставления. Я также обновил упомянутый emp контура DROP. Вместо того, чтобы поддерживать отдельную папку / файл для операторов drop, я просто читаю первую строку каждого файла sql и заменяю CREATE
на DROP
(просто убедитесь, что первая строка всегда просто CREATE PROCEDURE ProcName
). Таким образом, все процедуры в моей папке StoredProcs будут удаляться и воссоздаваться при каждом запуске Update-Database. Падение также завернуто в блок try-catch, если процедура новая. Чтобы число параметров процедуры работало, вам нужно убедиться, что вы завершаете блок BEGIN/END
вокруг вашего tsql, так как каждая строка файла считывается до BEGIN. Также убедитесь, что каждый параметр sp находится на новой строке.
// 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]); } }
Наслаждайтесь!
Как отметил Ладислав, DbContext
вообще сводит к минимуму логику в базе данных, но можно выполнить собственный SQL с помощью context.Database.ExecuteSqlCommand()
или context.Database.SqlQuery()
.