首先在Entity Framework中自动生成存储过程

时间:2016-08-09 14:51:19

标签: c# entity-framework

我有一组类A[1..n],它们都继承自抽象类B。这些A实例中的每一个都只添加了一个属性 - 外键映射到每个实例的单独表。每个外键列的名称都为ForeignKeyId,而不是表的名称,所以基本上我有一组除了名称之外几乎完全相同的表。

我想编写一个存储过程,使用一些特定的SQL分组和排序以及连接和诸如此类的东西来加载来自这些表的记录。重要的部分不是查询本身,而是自动创建具有特定名称的存储过程,而不是在迁移本身中手动逐行添加(这是此中最受欢迎的答案)问题:Create Stored Procedures using Entity Framework Code First?)。

我已尝试在MigrationCodeGenerator

中创建其他操作
public override ScaffoldedMigration Generate( string migrationId, 
            IEnumerable<MigrationOperation> operations, string sourceModel, 
            string targetModel, string @namespace, string className )
{
    IList<MigrationOperation> operationsList = operations as IList<MigrationOperation> ?? operations.ToList();            

    var drop = new DropProcedureOperation($"{className}_LoadVersion");
    var create = new CreateProcedureOperation($"{className}_LoadVersion", $"select * from {className}");

    operationsList.Add( drop );
    operationsList.Add(create);

    CSharpMigrationCodeGenerator generator = new CSharpMigrationCodeGenerator();

    return generator.Generate( migrationId, operationsList, sourceModel, targetModel, @namespace, className );
}

但是,我的迁移完全是空的:

public partial class TestMigration : DbMigration
{
    public override void Up()
    {
    }

    public override void Down()
    {
    }
}

一旦我可以让生成器开始创建任何东西,我可以从那里对其进行微调,但是我很难知道如何在迁移时创建存储过程。

1 个答案:

答案 0 :(得分:1)

所以经过一些额外的挖掘,我能够弄清楚如何完成我需要的东西。

我的所有存储过程都基于表结构,所以我可以检查迁移过程中发生了什么样的更改,并根据需要修改过程。 ScaffoldMigration函数包含给定迁移的操作列表,每个类型都为MigrationOperation。这个类有很多子类:https://msdn.microsoft.com/en-us/library/system.data.entity.migrations.model.migrationoperation(v=vs.113).aspx

由于存储过程至少需要用于构建存储过程的表名(因为我需要每个表存储一个proc),我需要检查操作是否是正确的类型,如果是,从中抽出正确的值:

foreach (MigrationOperation operation in operationsList)
{
    if (operation is CreateTableOperation)
    {
        CreateTableOperation op = (CreateTableOperation) operation;
        if (op.Name.Contains( ChangeTracker ))
                procOps.Add(CreateLoadVersionProc(op.Name));            
    }
}

procOps只是一个迁移操作列表:List<MigrationOperation> procOps = new List<MigrationOperation>();

CreateLoadVersionProc只返回一个新的CreateProcedureOperation对象:

private static CreateProcedureOperation CreateLoadVersionProc(string tableName)
{
    string proc = $@"select x.*
        from {tableName} x
        where x.CreatedTimeStamp >= @target";

    var op = new CreateProcedureOperation($"{tableName}_LoadVersion", proc);
    var dateParam = new ParameterModel(PrimitiveTypeKind.DateTime) {Name = "@target"};
    op.Parameters.Add(dateParam);           

    return op;
}

然后,回到我的ScaffoldMigration函数中,我只是将我创建的存储过程操作列表添加到传递给函数的操作列表中:

if (procOps.Any())
    operationsList.AddRange(procOps);

然后该函数继续进行CSharpMigrationGenerator创建和Generate函数调用以吐出迁移。