如何在SqlServerMigrationSqlGenerator中分离执行SQL代码生成方法?

时间:2017-09-21 19:38:26

标签: entity-framework-6

我想在通过Entity Framework创建的每个新表之后运行一个SQL脚本。

我为'CreateTableOperation'创建了一个覆盖:

protected override void Generate(CreateTableOperation createTableOperation)
{
    string tenantID = "tenantID";
    base.Generate(createTableOperation);
    //If the table contain the column "tenantID",
    if ((from x in createTableOperation.Columns
         where x.Name == tenantID
         select x).Any()
    )
    {
        //Add the Security Policies for this table
        using (var writer = Writer())
        {
            writer.WriteLine("ALTER SECURITY POLICY rls.tenantAccessPolicy ");
            //Note: dbo. is already part of the .Name, don't add it manually before .Name
            writer.WriteLine($"ADD FILTER PREDICATE rls.fn_tenantAccessPredicateWithSuperUser([{tenantID}]) ON [{createTableOperation.Name}], ");
            writer.WriteLine($"ADD BLOCK PREDICATE rls.fn_tenantAccessPredicateWithSuperUser([{tenantID}]) ON [{createTableOperation.Name}] ");
            Statement(writer);
        }
    }
}

假设我创建了一个新类'TEST'。 问题是当我在软件包管理器控制台中运行更新数据库时,SQL在一个大块中执行并创建一个错误,因为该表尚未创建,我正在尝试获取table.name Update-Database后的Package Manager结果:

CREATE TABLE [dbo].[TEST] (
    [ID] [int] NOT NULL IDENTITY,
    [NameTEST] [nvarchar](max),
    [TenantID] [int] NOT NULL,
    CONSTRAINT [PK_dbo.TEST] PRIMARY KEY ([ID])
)
ALTER SECURITY POLICY rls.tenantAccessPolicy 
ADD FILTER PREDICATE rls.fn_tenantAccessPredicateWithSuperUser([tenantID]) ON [dbo.TEST], 
ADD BLOCK PREDICATE rls.fn_tenantAccessPredicateWithSuperUser([tenantID]) ON [dbo.TEST] 

无法找到对象“dbo.TEST”,因为它不存在或您没有权限。 有没有办法在 base.Generate(createTableOperation); 和我的声明(作家); 之间打破? (我已经用“GO”尝试过多次没有太大成功的事情)。或者是我不应该在该方法中加入代码?

1 个答案:

答案 0 :(得分:0)

我找不到解决方案/文档来分隔Generate(CreateTableOperation createTableOperation).

中的代码/批处理SQL

我做的是

  • Generate(CreateTableOperation createTableOperation)方法

    中生成动态SQL脚本
        /// <summary>
        /// Generate dynamically named .sql file for CREATE and DROP Security Policies (Row-Level Security (Company can't see/insert data of another company))
        /// </summary>
        /// <param name="createTableOperation">Default parameter that comes with the override method.</param>
        protected override void Generate(CreateTableOperation createTableOperation)
        {
            base.Generate(createTableOperation);
        string fullFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\Migrations\\SQLscripts\\SecurityPolicies");
    
        //Remove the schema for the dynamic creation of the .sql filename else it throw an exception: 
        int indexOfDot = createTableOperation.Name.IndexOf(".");
        indexOfDot++; //Because it's 0 base, add 1 char
        string tableNameWithoutSchema = (indexOfDot < 0) ? createTableOperation.Name : createTableOperation.Name.Remove(0, indexOfDot);
    
        string filePathCreate = Path.Combine(fullFolderPath, $"CreateSecurityPolicies_{tableNameWithoutSchema}.sql");
        string filePathDrop = Path.Combine(fullFolderPath, $"DropSecurityPolicies_{tableNameWithoutSchema}.sql");
    
        //If .sql files doesn't exists, create them
        if (!File.Exists(filePathCreate))
        {
            using (StreamWriter sw = new StreamWriter(filePathCreate, true))
            {
                sw.WriteLine("ALTER SECURITY POLICY rls.tenantAccessPolicy");
                //Note: Don't concatenate 'dbo.{}' because 'createTableOperation.Name' already include 'dbo'
                sw.WriteLine($" ADD FILTER PREDICATE rls.fn_tenantAccessPredicateWithSuperUser(CompanyID) ON {createTableOperation.Name},");
                sw.WriteLine($" ADD BLOCK PREDICATE rls.fn_tenantAccessPredicateWithSuperUser(CompanyID) ON {createTableOperation.Name}");
                sw.WriteLine("GO");
                sw.Close();
            }
        }
    
        if (!File.Exists(filePathDrop))
        {
            using (StreamWriter sw = new StreamWriter(filePathDrop, true))
            {
                sw.WriteLine("ALTER SECURITY POLICY rls.tenantAccessPolicy");
                sw.WriteLine($" DROP FILTER PREDICATE ON {createTableOperation.Name},");
                sw.WriteLine($" DROP BLOCK PREDICATE ON {createTableOperation.Name}");
                sw.WriteLine("GO");
                sw.Close();
            }
        }
    
    
    }
    
  • 然后,将我的SQL脚本放在一个文件夹中,手动将其添加到我的解决方案中。

  • Add-Migration只是为了运行我的SQL脚本,方法是将代码添加到空的(最新的)迁移类中。

    public override void Up()
    {
        string sqlFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\Migrations\\SQLscripts\\CreateSecurityPolicies_Client.sql");
        string sqlText = System.IO.File.ReadAllText(sqlFilePath);
        Sql(sqlText);
    }
    
    public override void Down()
    {
        string sqlFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\Migrations\\SQLscripts\\DropSecurityPolicies_Client.sql");
        string sqlText = System.IO.File.ReadAllText(sqlFilePath);
        Sql(sqlText);
    }
    

这是我现在能想到的最好的。我希望它可以帮助其他EntityFramework程序员!