Code First Migrations and Stored Procedures

前端 未结 4 875
青春惊慌失措
青春惊慌失措 2020-12-05 10:19

I have just created a database and done my first migration (just a simple table add). Now I want to add some stored procedures which I have just added by writing the sql an

4条回答
  •  遥遥无期
    2020-12-05 10:30

    I will try to provide a different perspective because having SQL code within C# strings is not very appealing and one should expect to change such scripts within a tool that provides intellisense (e.g. SSMS).

    The following solution is implemented within a ASP.NET Core 2.0 Web API project.

    1. Maintain procedures in the development database using any convenient tool

    2. Generate procedures scripts:

      public class ProcedureItemMetadata
      {
          /// 
          /// SQL server side object identifier
          /// 
          [Key]
          public int ObjectId { get; set; }
      
          /// 
          /// schema name
          /// 
          public string SchemaName { get; set; }
      
          /// 
          /// procedure name
          /// 
          public string Name { get; set; }
      
          /// 
          /// procedure body
          /// 
          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\s+PROCEDURE\s+)",
               "CREATE OR ALTER PROCEDURE ", 
               RegexOptions.IgnoreCase);
      
            return replaced;
      }
      

    This is a manual process, but allows to obtain procedures whenever their development is ready. Also, it can easily be extended to other types of objects (e.g. views).

    1. Create a folder within solution to hold scripts to be run at application startup (e.g. _SQL)

    2. Copy generated script within the folder (e.g. all_procedures.sql)

    One advantage of storing scripts like this is that the IDE might automatically validate the syntax + highlight stuff etc.

    1. Create "seed" code to automatically run when application starts

      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);
              }
          }
      }
      

    This approach allows for any idempotent scripts that are not easily maintained through migrations to be managed.

提交回复
热议问题