31

我刚刚创建了一个数据库并完成了我的第一次迁移(只是一个简单的表添加)。现在我想添加一些我刚刚添加的存储过程,方法是编写 sql 并在 Management Studio 中执行它。但如果可能的话,我想在迁移中包含这些存储过程,以便保存它们,并且我可以对它们运行 Up 或 Down 方法。这可能吗?如果可以,需要使用什么语法?还是我只需要使用 Management Studio 添加/编辑/删除它们?

4

4 回答 4

27

我已经这样做了......

在当前的迁移类中 -

public partial class MyMigration : DbMigration
{
    public override void Up()
    {
        ... other table creation logic

        // This command executes the SQL you have written
        // to create the stored procedures
        Sql(InstallScript);

        // or, to alter stored procedures
        Sql(AlterScript);
    }

    public override void Down()
    {
        ... other table removal logic

        // This command executes the SQL you have written
        // to drop the stored procedures
        Sql(UninstallScript);

        // or, to rollback stored procedures
        Sql(RollbackScript);
    }

    private const string InstallScript = @"
        CREATE PROCEDURE [dbo].[MyProcedure]
        ... SP logic here ...
    ";

    private const string UninstallScript = @"
        DROP PROCEDURE [dbo].[MyProcedure];
    ";

    // or for alters
    private const string AlterScript = @"
        ALTER PROCEDURE [dbo].[AnotherProcedure]
        ... Newer SP logic here ...
    ";

    private const string RollbackScript = @"
        ALTER PROCEDURE [dbo].[AnotherProcedure]
        ... Previous / Old SP logic here ...
    ";
}
于 2013-05-16T13:44:27.930 回答
13

我正在使用 EF6,DbMigration该类提供了创建/更改/删除存储过程的方法

  • 创建一个新的存储过程

    public partial class MyFirstMigration : DbMigration
    {
        public override void Up()
        {
            // Create a new store procedure
            CreateStoredProcedure("dbo.DequeueMessages"
            // These are stored procedure parameters
            , c => new{                
                MessageCount = c.Int()
            },
            // Here is the stored procedure body
            @"
            SET NOCOUNT ON;
            SELECT TOP (@MessageCount)
                *
            FROM
                dbo.MyTable;
            ");
        }
    
        public override void Down()
        {
            // Delete the stored procedure
            DropStoredProcedure("dbo.DequeueMessages");                
        }
    }
    
  • 修改存储过程

    public partial class MySecondMigration : DbMigration
    {
        public override void Up()
        {
            // Modify an existing stored procedure
            AlterStoredProcedure("dbo.DequeueMessages"
            // These are new stored procedure parameters
            , c => new{                
                MessageCount = c.Int(),
                StatusId = c.Int()
            },
            // Here is the new stored procedure body
            @"
            SET NOCOUNT ON;
            SELECT TOP (@MessageCount)
                *
            FROM
                dbo.MyTable
            WHERE
                StatusId = @StatusId;
            ");
        }
    
        public override void Down()
        {
            // Rollback to the previous stored procedure
            // Modify an existing stored procedure
            AlterStoredProcedure("dbo.DequeueMessages"
            // These are old stored procedure parameters
            , c => new{                
                MessageCount = c.Int()
            },
            // Here is the old stored procedure body
            @"
            SET NOCOUNT ON;
            SELECT TOP (@MessageCount)
                *
            FROM
                dbo.MyTable;
            ");              
        }
    }
    
于 2016-05-17T01:16:05.977 回答
1
namespace QuickProject.Migrations
{
    using System;
    using System.Data.Entity.Migrations;


public partial class CreateStoredProcedure_GellAllAgents : DbMigration
{
    public override void Up()
    {
        CreateStoredProcedure("dbo.GellAllAgents", c => new
        {
            DisplayLength = c.Int(10),
            DisplayStart = c.Int(0),
            UserName = c.String(maxLength: 255, defaultValueSql: "NULL"),
            FullName = c.String(maxLength: 255, defaultValueSql: "NULL"),
            PhoneNumber = c.String(maxLength: 255, defaultValueSql: "NULL"),
            LocationDescription = c.String(maxLength: 255, defaultValueSql: "NULL"),
            AgentStatusId = c.Int(defaultValueSql: "NULL"),
            AgentTypeId = c.Int(defaultValueSql: "NULL")
        }, StoredProcedureBody);
    }

    public override void Down()
    {
        DropStoredProcedure("dbo.GellAllAgents");
    }


    private const string StoredProcedureBody = @"
Declare @FirstRec int, @LastRec int
Set @FirstRec = @DisplayStart;
Set @LastRec = @DisplayStart + @DisplayLength;

With CTE_AspNetUsers as
(
     Select ROW_NUMBER() over (order by AspNetUsers.Id) as RowNum,
         COUNT(*) over() as TotalCount, AspNetUsers.Id, AspNetUsers.FullName, AspNetUsers.UserName, AspNetUsers.PhoneNumber, Locations.Desciption as LocationDescription, Cities.Name as LocationCity, AgentStatus.Name as AgentStatusName, AgentTypes.Name as AgentTypeName
         from AspNetUsers
     join Locations on AspNetUsers.LocationId = Locations.id
     join Cities on Locations.CityId = Cities.Id
     join AgentStatus on AspNetUsers.AgentStatusId = AgentStatus.Id
     join AgentTypes on AspNetUsers.AgentTypeId = AgentTypes.Id
     where (Discriminator = 'Agent' 
         and (@UserName is null or UserName like '%' + @UserName + '%')
         and (@FullName is null or FullName like '%' + @FullName + '%')
         and (@PhoneNumber is null or PhoneNumber like '%' + @PhoneNumber + '%')
         and (@LocationDescription is null or  @LocationDescription like '%' + (select Cities.Name from Cities where Locations.CityId = Cities.Id) + '%' or  @LocationDescription like '%' + Desciption + '%')
         and (@AgentStatusId is null or AgentStatusId = @AgentStatusId)
         and (@AgentTypeId is null or AgentTypeId = @AgentTypeId)
     )
     group by AspNetUsers.Id, AspNetUsers.FullName,AspNetUsers.UserName, AspNetUsers.PhoneNumber, Locations.Desciption, Cities.Name, AgentStatus.Name, AgentTypes.Name
)
Select *
from CTE_AspNetUsers
where RowNum > @FirstRec and RowNum <= @LastRec
";
}
}

结果,当您在 SQL Server 中查看/修改 SP 时,这就是它显示“ALTER PROCEDURE”的原因

在此处输入图像描述

于 2018-10-06T13:23:34.417 回答
0

我将尝试提供不同的视角,因为在 C# 字符串中包含 SQL 代码并不是很吸引人,人们应该期望在提供智能感知的工具(例如 SSMS)中更改此类脚本。

以下解决方案在 ASP.NET Core 2.0 Web API 项目中实现。

  1. 使用任何方便的工具维护开发数据库中的程序

  2. 生成程序脚本:

    public class ProcedureItemMetadata
    {
        /// <summary>
        /// SQL server side object identifier
        /// </summary>
        [Key]
        public int ObjectId { get; set; }
    
        /// <summary>
        /// schema name
        /// </summary>
        public string SchemaName { get; set; }
    
        /// <summary>
        /// procedure name
        /// </summary>
        public string Name { get; set; }
    
        /// <summary>
        /// procedure body
        /// </summary>
        public string Definition { get; set; }
    }
    
    
    public string GetProceduresScript()
    {
       var query = Context.ProcedureItemMetadata.AsNoTracking().FromSql(@"
          SELECT ao.object_id as ObjectId, SCHEMA_NAME(ao.schema_id) as SchemaName, ao.name, sm.definition
          FROM sys.all_objects ao 
          JOIN sys.sql_modules sm ON sm.object_id = ao.object_id
          WHERE ao.type = 'P'
             and execute_as_principal_id IS NULL
          order by 1;");
    
          var list = query.ToList();
          string text = string.Join($" {Base.Constants.General.ScriptGeneratorSeparator}\n", list.Select(p => p.Definition));
    
          // replace create with create or alter
          string replaced = Regex.Replace(text,
             @"(?<create>CREATE\s+PROCEDURE\s+)",
             "CREATE OR ALTER PROCEDURE ", 
             RegexOptions.IgnoreCase);
    
          return replaced;
    }
    

这是一个手动过程,但允许在开发准备就绪时获取程序。此外,它可以很容易地扩展到其他类型的对象(例如视图)。

  1. 在解决方案中创建一个文件夹以保存要在应用程序启动时运行的脚本(例如 _SQL)

  2. 在文件夹中复制生成的脚本(例如 all_procedures.sql)

像这样存储脚本的一个优点是 IDE 可能会自动验证语法 + 突出显示的内容等。

  1. 创建“种子”代码以在应用程序启动时自动运行

    private static void EnsureSqlObjects(CustomContext context)
    {
        string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "_Sql");
        foreach (var file in Directory.GetFiles(path, "*.sql"))
        {
            string fileText = File.ReadAllText(file);
            // escaping { } for those rare cases when sql code contains {..}
            // as ExecuteSqlCommand tries to replace them with params values
            fileText = fileText.Replace("{", "{{");
            fileText = fileText.Replace("}", "}}");
    
            // splitting objects (cannot run more than one DDL in a command)
            string[] ddlParts = fileText.Split(Base.Constants.General.ScriptGeneratorSeparator, StringSplitOptions.RemoveEmptyEntries);
            foreach (string ddl in ddlParts)
            {
                context.Database.ExecuteSqlCommand(ddl);
            }
        }
    }
    

这种方法允许管理通过迁移不容易维护的任何幂等脚本。

于 2019-02-14T07:58:28.770 回答