首页 > 解决方案 > Unable to generate BIML script for Tiering in SSIS

问题描述

I have a situation where my master biml generates 150 Execute package task.I need to generate sequence containers so that each of them holds (150/10)15 Execute package task per sequence container in the master package.

Could you please help me to find an appropriate solution any ideas/Working exmaples/code base are welcome!!

<Tasks> 
    <# foreach (var package in RootNode.Packages) { #> 
         <ExecutePackage Name="Execute <#=package.Name#>" > 
              <ExternalProjectPackage Package="<#=package.PackageFileName#>" /> 
         </ExecutePackage>
    <# } #>
</Tasks> 

标签: ssisbiml

解决方案


这个答案将利用 Biml 的一些高级概念。第一个将是分层,因此我们将在第 1 层生成 150 个包。然后在第 2 层(或任何大于前一层的数字),我们将能够参考第 0 层到(最大层数 - 1)。

第 0 层是静态/平面 Biml(在本例中我们没有)。由于我们将循环生成子包,它将自动位于第 1 层,但我选择在此处明确说明,以防您有前驱但动态的任务要解决

<#* .... #>是一个超级强大的注释结构,被 Biml 编译器忽略

<#+ .... #>是用于将显式方法和类添加到 Biml 中的构造

我们还将使用扩展方法将我们的包大致拆分为组,然后填充到序列容器中。

第一层

此代码生成空白 SSIS 包,名称范围从 so_54773502_000 到 so_54773502_149(总共 150 个)

<#@ template tier="1" #>
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
    <Packages>
<#foreach (int index in Enumerable.Range(0, 150)){#>
    <Package Name="so_54773502_<#= string.Format("{0:000}", index) #>" />
<#}#>
    </Packages>
</Biml>

2级

在这里,我们指定我们想要多少个并行容器。该Split方法的结果是一个列表列表。对于外部容器列表中的每个元素,我们需要添加一个序列容器。对于弹出列表中的每个元素,我们需要枚举它并执行一个包任务。

<#@ template tier="2" #>
<#
int taskCountPerContainer = 10;
int currentContainerNumber = 0;
#>
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
    <Packages>
        <Package Name="master">
            <Tasks>
<#* 
    This is such a fun bit of LINQ. I used the Split extension so handily defined on the linked question
    I pass in a List of package names and how many buckets I want and it returns a list of lists

    From there, we enumerate through the list bucket and for each element we find, we create a sequence
    container. Then, for each element in the bucket, we add an Execute Package Task.

    I was unable to Split an instance of AstPackageNodes as it resulted in the error below but the only reason
    your sample needed the full object was to provide both Name and PackageFileName properties. We can derive
    the second given the first

// foreach(var outerlist in Split(this.RootNode.Packages.ToList<AstPackageNode>(),taskCountPerContainer)){    
// results in this error. 
// Destination array was not long enough. Check destIndex and length, and the array's lower bounds.    
// TODO: Check with Varigence or run in C# project

*#>
                <#foreach(var listOfPackages in Split(this.RootNode.Packages.Select(x => x.Name).ToList<string>(), taskCountPerContainer)){#>
                <Container Name="SEQC_<#=currentContainerNumber++#>" ConstraintMode="Linear">
                    <Tasks>
                    <#foreach(var packageName in listOfPackages){#>
                        <ExecutePackage Name="EPT <#=packageName#>"><ExternalProjectPackage Package="<#=packageName#>.dtsx"/></ExecutePackage>
                    <#}#>
                    </Tasks>
                </Container>
                <#}#>
            </Tasks>
        </Package>
    </Packages>
</Biml>

<#+
// https://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq
public static IList<List<T>> Split<T>(IList<T> source, int buckets)
{
    return  source
        .Select((x, i) => new { Index = i, Value = x })
        .GroupBy(x => x.Index / buckets)
        .Select(x => x.Select(v => v.Value).ToList())
        .ToList();
}

#>

最终结果

看,很多包都被执行了!

在此处输入图像描述


推荐阅读